diff options
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; } |
