summaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader/ECTesterReader.java
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java (renamed from src/cz/crcs/ectester/reader/ECTester.java)215
1 files changed, 97 insertions, 118 deletions
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index 550e070..5e3a3fe 100644
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ b/src/cz/crcs/ectester/reader/ECTesterReader.java
@@ -23,12 +23,19 @@ package cz.crcs.ectester.reader;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.cli.CLITools;
+import cz.crcs.ectester.common.ec.EC_Params;
+import cz.crcs.ectester.common.output.OutputLogger;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.ec.EC_Category;
-import cz.crcs.ectester.reader.ec.EC_Data;
-import cz.crcs.ectester.reader.ec.EC_Params;
-import cz.crcs.ectester.reader.output.*;
+import cz.crcs.ectester.reader.output.ResponseWriter;
+import cz.crcs.ectester.reader.output.TextTestWriter;
+import cz.crcs.ectester.reader.output.XMLTestWriter;
+import cz.crcs.ectester.reader.output.YAMLTestWriter;
import cz.crcs.ectester.reader.response.Response;
import cz.crcs.ectester.reader.test.*;
import javacard.security.KeyPair;
@@ -38,9 +45,13 @@ import javax.smartcardio.CardException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.nio.file.Files;
-import java.util.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Scanner;
import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH;
+import static cz.crcs.ectester.applet.ECTesterApplet.Signature_ALG_ECDSA_SHA;
/**
* Reader part of ECTester, a tool for testing Elliptic curve support on javacards.
@@ -49,18 +60,15 @@ import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH
* @author Jan Jancar johny@neuromancer.sk
* @version v0.1.0
*/
-public class ECTester {
-
+public class ECTesterReader {
private CardMngr cardManager;
private OutputLogger logger;
- private TestWriter testWriter;
private ResponseWriter respWriter;
- private EC_Store dataStore;
private Config cfg;
private Options opts = new Options();
private static final String VERSION = "v0.1.0";
- private static final String DESCRIPTION = "ECTester " + VERSION + ", a javacard Elliptic Curve Cryptograhy support tester/utility.";
+ private static final String DESCRIPTION = "ECTesterReader " + VERSION + ", a javacard Elliptic Curve Cryptography support tester/utility.";
private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda <petr@svenda.com>";
private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n";
private static final String CLI_FOOTER = "\n" + LICENSE;
@@ -76,11 +84,10 @@ public class ECTester {
//if help, print and quit
if (cli.hasOption("help")) {
- help();
+ CLITools.help("ECTesterReader.jar", CLI_HEADER, opts, CLI_FOOTER, true);
return;
} else if (cli.hasOption("version")) {
- System.out.println(DESCRIPTION);
- System.out.println(LICENSE);
+ CLITools.version(DESCRIPTION, LICENSE);
return;
}
cfg = new Config();
@@ -90,10 +97,9 @@ public class ECTester {
return;
}
- dataStore = new EC_Store();
//if list, print and quit
if (cli.hasOption("list-named")) {
- list();
+ CLITools.listNamed(EC_Store.getInstance(), cli.getOptionValue("list-named"));
return;
}
@@ -116,22 +122,7 @@ public class ECTester {
// Setup logger, testWriter and respWriter
logger = new OutputLogger(true, cfg.log);
- if (cfg.format == null) {
- testWriter = new TextTestWriter(logger.getPrintStream());
- } else {
- switch (cfg.format) {
- case "text":
- testWriter = new TextTestWriter(logger.getPrintStream());
- break;
- case "xml":
- testWriter = new XMLTestWriter(logger.getOutputStream());
- break;
- case "yaml":
- case "yml":
- testWriter = new YAMLTestWriter(logger.getPrintStream());
- break;
- }
- }
+
respWriter = new ResponseWriter(logger.getPrintStream());
//do action
@@ -187,9 +178,10 @@ public class ECTester {
System.err.println("File " + fnfe.getMessage() + " not found.");
} catch (ParseException | IOException ex) {
System.err.println(ex.getMessage());
- } catch (CardException ex) {
+ } catch (CardException | TestException ex) {
if (logger != null)
logger.println(ex.getMessage());
+ ex.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} finally {
@@ -213,8 +205,7 @@ public class ECTester {
* -e / --export
* -g / --generate [amount]
* -t / --test [test_suite]
- * -dh / --ecdh [count]
- * -dhc / --ecdhc [count]
+ * -dh / --ecdh [count]]
* -dsa / --ecdsa [count]
* -ln / --list-named [obj]
*
@@ -248,6 +239,7 @@ public class ECTester {
* -s / --simulate
* -y / --yes
* -ka/ --ka-type <type>
+ * -sig/--sig-type <type>
*/
OptionGroup actions = new OptionGroup();
actions.setRequired(true);
@@ -256,9 +248,8 @@ public class ECTester {
actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build());
actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build());
actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build());
- actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build());
- actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH, [count] times.").hasArg().argName("count").optionalArg(true).build());
- actions.addOption(Option.builder("dhc").longOpt("ecdhc").desc("Do ECDHC, [count] times.").hasArg().argName("count").optionalArg(true).build());
+ actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- twist:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build());
+ actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do EC KeyAgreement (ECDH...), [count] times.").hasArg().argName("count").optionalArg(true).build());
actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build());
opts.addOptionGroup(actions);
@@ -303,45 +294,13 @@ public class ECTester {
opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build());
opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build());
+ opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build());
CommandLineParser parser = new DefaultParser();
return parser.parse(opts, args);
}
/**
- * Prints help.
- */
- private void help() {
- HelpFormatter help = new HelpFormatter();
- help.setOptionComparator(null);
- help.printHelp("ECTester.jar", CLI_HEADER, opts, CLI_FOOTER, true);
- }
-
- /**
- * List categories and named curves.
- */
- private void list() {
- Map<String, EC_Category> categories = dataStore.getCategories();
- if (cfg.listNamed == null) {
- // print all categories, briefly
- for (EC_Category cat : categories.values()) {
- System.out.println(cat);
- }
- } else if (categories.containsKey(cfg.listNamed)) {
- // print given category
- System.out.println(categories.get(cfg.listNamed));
- } else {
- // print given object
- EC_Data object = dataStore.getObject(EC_Data.class, cfg.listNamed);
- if (object != null) {
- System.out.println(object);
- } else {
- System.err.println("Named object " + cfg.listNamed + " not found!");
- }
- }
- }
-
- /**
* Exports default card/simulation EC domain parameters to output file.
*
* @throws CardException if APDU transmission fails
@@ -386,8 +345,9 @@ public class ECTester {
private void generate() throws CardException, IOException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send();
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
+ Response allocate = new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send();
+ respWriter.outputResponse(allocate);
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
FileWriter keysFile = new FileWriter(cfg.output);
keysFile.write("index;time;pubW;privS\n");
@@ -417,8 +377,8 @@ public class ECTester {
}
respWriter.outputResponse(response);
- String pub = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
- String priv = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
+ 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;%s;%s\n", generated, elapsed / 1000000, pub, priv);
keysFile.write(line);
keysFile.flush();
@@ -436,20 +396,38 @@ public class ECTester {
* @throws CardException if APDU transmission fails
* @throws IOException if an IO error occurs when writing to key file.
*/
- private void test() throws IOException, CardException {
- TestSuite suite;
+ private void test() throws IOException, TestException, ParserConfigurationException {
+ TestWriter writer = null;
+ if (cfg.format == null) {
+ writer = new TextTestWriter(logger.getPrintStream());
+ } else {
+ switch (cfg.format) {
+ case "text":
+ writer = new TextTestWriter(logger.getPrintStream());
+ break;
+ case "xml":
+ writer = new XMLTestWriter(logger.getOutputStream());
+ break;
+ case "yaml":
+ case "yml":
+ writer = new YAMLTestWriter(logger.getPrintStream());
+ break;
+ }
+ }
+
+ CardTestSuite suite;
switch (cfg.testSuite) {
case "default":
- suite = new DefaultSuite(dataStore, cfg);
+ suite = new CardDefaultSuite(writer, cfg, cardManager);
break;
case "test-vectors":
- suite = new TestVectorSuite(dataStore, cfg);
+ suite = new CardTestVectorSuite(writer, cfg, cardManager);
break;
default:
- // These tests are dangerous, prompt before them.
+ // These run are dangerous, prompt before them.
System.out.println("The test you selected (" + cfg.testSuite + ") is potentially dangerous.");
- System.out.println("Some of these tests have caused temporary DoS of some cards.");
+ System.out.println("Some of these run have caused temporary DoS of some cards.");
if (!cfg.yes) {
System.out.print("Do you want to proceed? (y/n): ");
Scanner in = new Scanner(System.in);
@@ -459,17 +437,18 @@ public class ECTester {
}
in.close();
}
-
-
switch (cfg.testSuite) {
case "wrong":
- suite = new WrongCurvesSuite(dataStore, cfg);
+ suite = new CardWrongCurvesSuite(writer, cfg, cardManager);
break;
case "composite":
- suite = new CompositeCurvesSuite(dataStore, cfg);
+ suite = new CardCompositeCurvesSuite(writer, cfg, cardManager);
break;
case "invalid":
- suite = new InvalidCurvesSuite(dataStore, cfg);
+ suite = new CardInvalidCurvesSuite(writer, cfg, cardManager);
+ break;
+ case "twist":
+ suite = new CardTwistTestSuite(writer, cfg, cardManager);
break;
default:
System.err.println("Unknown test suite.");
@@ -478,9 +457,7 @@ public class ECTester {
break;
}
- TestRunner runner = new TestRunner(suite, testWriter);
- suite.setup(cardManager);
- runner.run();
+ suite.run();
}
/**
@@ -492,9 +469,9 @@ public class ECTester {
private void ecdh() throws IOException, CardException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
List<Response> prepare = new LinkedList<>();
- prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.kaType).send()); // Prepare KeyAgreement or required type
+ prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.ECKAType).send()); // Prepare KeyAgreement or required type
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass);
if (curve != null)
prepare.add(curve.send());
@@ -508,21 +485,26 @@ public class ECTester {
List<Command> generate = new LinkedList<>();
generate.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH));
if (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) {
- generate.add(Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_REMOTE));
+ generate.add(Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE));
}
FileWriter out = null;
if (cfg.output != null) {
out = new FileWriter(cfg.output);
- out.write("index;time;secret\n");
+ out.write("index;time;pubW;privS;secret\n");
}
int retry = 0;
int done = 0;
- while (done < cfg.ECDHCount) {
+ while (done < cfg.ECKACount) {
List<Response> ecdh = Command.sendAll(generate);
- Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, cfg.ECDHKA).send();
+ Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
+ ecdh.add(export);
+ byte pubkey_bytes[] = export.getParameter(pubkey, EC_Consts.PARAMETER_W);
+ byte privkey_bytes[] = export.getParameter(privkey, EC_Consts.PARAMETER_S);
+
+ Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, cfg.ECKAType).send();
ecdh.add(perform);
for (Response r : ecdh) {
respWriter.outputResponse(r);
@@ -539,7 +521,7 @@ public class ECTester {
}
if (out != null) {
- out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false)));
+ out.write(String.format("%d;%d;%s;%s;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(perform.getSecret(), false)));
}
++done;
@@ -571,15 +553,16 @@ public class ECTester {
Command generate;
if (cfg.anyKeypart) {
- generate = Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL);
+ generate = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL);
} else {
generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
}
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
List<Response> prepare = new LinkedList<>();
+ prepare.add(new Command.AllocateSignature(cardManager, cfg.ECDSAType).send());
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
if (curve != null)
prepare.add(curve.send());
@@ -599,7 +582,7 @@ public class ECTester {
List<Response> ecdsa = new LinkedList<>();
ecdsa.add(generate.send());
- Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, data).send();
+ Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send();
ecdsa.add(perform);
for (Response r : ecdsa) {
respWriter.outputResponse(r);
@@ -616,7 +599,7 @@ public class ECTester {
}
if (out != null) {
- out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false)));
+ out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(perform.getSignature(), false)));
}
++done;
@@ -629,18 +612,18 @@ public class ECTester {
}
public static void main(String[] args) {
- ECTester app = new ECTester();
+ ECTesterReader app = new ECTesterReader();
app.run(args);
}
public static class Config {
//Options
- public int bits;
+ public short bits;
public boolean all;
public boolean primeField = false;
public boolean binaryField = false;
- public byte kaType = KeyAgreement_ALG_EC_SVDP_DH;
+
public String namedCurve;
public String curveFile;
@@ -674,9 +657,10 @@ public class ECTester {
public String listNamed;
public String testSuite;
public int generateAmount;
- public int ECDHCount;
- public byte ECDHKA;
+ public int ECKACount;
+ public byte ECKAType = KeyAgreement_ALG_EC_SVDP_DH;
public int ECDSACount;
+ public byte ECDSAType = Signature_ALG_ECDSA_SHA;
/**
* Reads and validates options, also sets defaults.
@@ -685,11 +669,11 @@ public class ECTester {
* @return whether the options are valid.
*/
boolean readOptions(CommandLine cli) {
- bits = Integer.parseInt(cli.getOptionValue("bit-size", "0"));
+ bits = Short.parseShort(cli.getOptionValue("bit-size", "0"));
all = cli.hasOption("all");
primeField = cli.hasOption("fp");
binaryField = cli.hasOption("f2m");
- kaType = Byte.parseByte(cli.getOptionValue("ka-type", "1"));
+
namedCurve = cli.getOptionValue("named-curve");
customCurve = cli.hasOption("custom");
@@ -770,7 +754,6 @@ public class ECTester {
System.err.println("You have to specify curve bit-size with -b");
return false;
}
-
} else if (cli.hasOption("generate")) {
if (primeField == binaryField) {
System.err.print("Need to specify field with -fp or -f2m. (not both)");
@@ -801,13 +784,12 @@ public class ECTester {
}
testSuite = cli.getOptionValue("test", "default").toLowerCase();
- String[] tests = new String[]{"default", "composite", "invalid", "test-vectors", "wrong"};
+ String[] tests = new String[]{"default", "composite", "invalid", "test-vectors", "wrong", "twist"};
if (!Arrays.asList(tests).contains(testSuite)) {
System.err.println("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests));
return false;
}
-
- } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) {
+ } else if (cli.hasOption("ecdh")) {
if (primeField == binaryField) {
System.err.print("Need to specify field with -fp or -f2m. (not both)");
return false;
@@ -817,18 +799,13 @@ public class ECTester {
return false;
}
- if (cli.hasOption("ecdh")) {
- ECDHCount = Integer.parseInt(cli.getOptionValue("ecdh", "1"));
- ECDHKA = EC_Consts.KA_ECDH;
- } else if (cli.hasOption("ecdhc")) {
- ECDHCount = Integer.parseInt(cli.getOptionValue("ecdhc", "1"));
- ECDHKA = EC_Consts.KA_ECDHC;
- }
- if (ECDHCount <= 0) {
+ ECKACount = Integer.parseInt(cli.getOptionValue("ecdh", "1"));
+ if (ECKACount <= 0) {
System.err.println("ECDH count cannot be <= 0.");
return false;
}
+ ECKAType = CardUtil.parseKAType(cli.getOptionValue("ka-type", "1"));
} else if (cli.hasOption("ecdsa")) {
if (primeField == binaryField) {
System.err.print("Need to specify field with -fp or -f2m. (but not both)");
@@ -849,6 +826,8 @@ public class ECTester {
System.err.println("ECDSA count cannot be <= 0.");
return false;
}
+
+ ECDSAType = CardUtil.parseSigType(cli.getOptionValue("sig-type", "17"));
}
return true;
}