summaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader/ECTester.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/reader/ECTester.java')
-rw-r--r--src/cz/crcs/ectester/reader/ECTester.java856
1 files changed, 0 insertions, 856 deletions
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java
deleted file mode 100644
index 550e070..0000000
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (c) 2016-2017 Petr Svenda <petr@svenda.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package cz.crcs.ectester.reader;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-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.response.Response;
-import cz.crcs.ectester.reader.test.*;
-import javacard.security.KeyPair;
-import org.apache.commons.cli.*;
-
-import javax.smartcardio.CardException;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.*;
-import java.nio.file.Files;
-import java.util.*;
-
-import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH;
-
-/**
- * Reader part of ECTester, a tool for testing Elliptic curve support on javacards.
- *
- * @author Petr Svenda petr@svenda.com
- * @author Jan Jancar johny@neuromancer.sk
- * @version v0.1.0
- */
-public class ECTester {
-
- 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 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;
-
- 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[] INSTALL_DATA = new byte[10];
-
- private void run(String[] args) {
- try {
- CommandLine cli = parseArgs(args);
-
- //if help, print and quit
- if (cli.hasOption("help")) {
- help();
- return;
- } else if (cli.hasOption("version")) {
- System.out.println(DESCRIPTION);
- System.out.println(LICENSE);
- return;
- }
- cfg = new Config();
-
- //if not, read other options first, into attributes, then do action
- if (!cfg.readOptions(cli)) {
- return;
- }
-
- dataStore = new EC_Store();
- //if list, print and quit
- if (cli.hasOption("list-named")) {
- list();
- return;
- }
-
- //init CardManager
- cardManager = new CardMngr(cfg.verbose, cfg.simulate);
-
- //connect or simulate connection
- if (cfg.simulate) {
- if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) {
- System.err.println("Failed to establish a simulator.");
- System.exit(1);
- }
- } else {
- if (!cardManager.connectToCardSelect()) {
- System.err.println("Failed to connect to card.");
- System.exit(1);
- }
- cardManager.send(SELECT_ECTESTERAPPLET);
- }
-
- // 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
- if (cli.hasOption("export")) {
- export();
- } else if (cli.hasOption("generate")) {
- generate();
- } else if (cli.hasOption("test")) {
- test();
- } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) {
- ecdh();
- } else if (cli.hasOption("ecdsa")) {
- ecdsa();
- }
-
- //disconnect
- cardManager.disconnectFromCard();
- logger.close();
-
- } catch (MissingOptionException moex) {
- System.err.println("Missing required options, one of:");
- for (Object opt : moex.getMissingOptions().toArray()) {
- if (opt instanceof OptionGroup) {
- for (Option o : ((OptionGroup) opt).getOptions()) {
- System.err.print("-" + o.getOpt());
-
- if (o.hasLongOpt()) {
- System.err.print("\t/ --" + o.getLongOpt() + " ");
- }
-
- if (o.hasArg()) {
- if (o.hasOptionalArg()) {
- System.err.print("[" + o.getArgName() + "] ");
- } else {
- System.err.print("<" + o.getArgName() + "> ");
- }
- }
-
- if (o.getDescription() != null) {
- System.err.print("\t\t\t" + o.getDescription());
- }
- System.err.println();
- }
- } else if (opt instanceof String) {
- System.err.println(opt);
- }
- }
- } catch (MissingArgumentException maex) {
- System.err.println("Option, " + maex.getOption().getOpt() + " requires an argument: " + maex.getOption().getArgName());
- } catch (NumberFormatException nfex) {
- System.err.println("Not a number. " + nfex.getMessage());
- } catch (FileNotFoundException fnfe) {
- System.err.println("File " + fnfe.getMessage() + " not found.");
- } catch (ParseException | IOException ex) {
- System.err.println(ex.getMessage());
- } catch (CardException ex) {
- if (logger != null)
- logger.println(ex.getMessage());
- } catch (ParserConfigurationException e) {
- e.printStackTrace();
- } finally {
- if (logger != null)
- logger.flush();
- }
- }
-
- /**
- * Parses command-line options.
- *
- * @param args cli arguments
- * @return parsed CommandLine object
- * @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]
- * -dhc / --ecdhc [count]
- * -dsa / --ecdsa [count]
- * -ln / --list-named [obj]
- *
- * Options:
- * -b / --bit-size <b> // -a / --all
- *
- * -fp / --prime-field
- * -f2m / --binary-field
- *
- * -u / --custom
- * -nc / --named-curve <cat/id>
- * -c / --curve <curve_file> field,a,b,gx,gy,r,k
- *
- * -pub / --public <pubkey_file> wx,wy
- * -npub / --named-public <cat/id>
- *
- * -priv / --private <privkey_file> s
- * -npriv / --named-private <cat/id>
- *
- * -k / --key <key_file> wx,wy,s
- * -nk / --named-key <cat/id>
- *
- * -v / --verbose
- *
- * -i / --input <input_file>
- * -o / --output <output_file>
- * --format <format>
- * -l / --log [log_file]
- *
- * -f / --fresh
- * -s / --simulate
- * -y / --yes
- * -ka/ --ka-type <type>
- */
- OptionGroup actions = new OptionGroup();
- actions.setRequired(true);
- actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build());
- actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build());
- 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("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build());
-
- opts.addOptionGroup(actions);
-
- OptionGroup size = new OptionGroup();
- size.addOption(Option.builder("b").longOpt("bit-size").desc("Set curve size.").hasArg().argName("bits").build());
- size.addOption(Option.builder("a").longOpt("all").desc("Test all curve sizes.").build());
- opts.addOptionGroup(size);
-
- opts.addOption(Option.builder("fp").longOpt("prime-field").desc("Use a prime field.").build());
- opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use a binary field.").build());
-
- OptionGroup curve = new OptionGroup();
- curve.addOption(Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").build());
- curve.addOption(Option.builder("c").longOpt("curve").desc("Use curve from file <curve_file> (field,a,b,gx,gy,r,k).").hasArg().argName("curve_file").build());
- curve.addOption(Option.builder("u").longOpt("custom").desc("Use a custom curve (applet-side embedded, SECG curves).").build());
- opts.addOptionGroup(curve);
-
- OptionGroup pub = new OptionGroup();
- pub.addOption(Option.builder("npub").longOpt("named-public").desc("Use public key from KeyDB: <cat/id>").hasArg().argName("cat/id").build());
- pub.addOption(Option.builder("pub").longOpt("public").desc("Use public key from file <pubkey_file> (wx,wy).").hasArg().argName("pubkey_file").build());
- opts.addOptionGroup(pub);
-
- OptionGroup priv = new OptionGroup();
- priv.addOption(Option.builder("npriv").longOpt("named-private").desc("Use private key from KeyDB: <cat/id>").hasArg().argName("cat/id").build());
- priv.addOption(Option.builder("priv").longOpt("private").desc("Use private key from file <privkey_file> (s).").hasArg().argName("privkey_file").build());
- opts.addOptionGroup(priv);
-
- OptionGroup key = new OptionGroup();
- key.addOption(Option.builder("nk").longOpt("named-key").desc("Use keyPair from KeyDB: <cat/id>").hasArg().argName("cat/id").build());
- key.addOption(Option.builder("k").longOpt("key").desc("Use keyPair from fileĀ <key_file> (wx,wy,s).").hasArg().argName("key_file").build());
- opts.addOptionGroup(key);
-
- opts.addOption(Option.builder("i").longOpt("input").desc("Input from fileĀ <input_file>, for ECDSA signing.").hasArg().argName("input_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("v").longOpt("verbose").desc("Turn on verbose logging.").build());
- opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").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());
- 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());
-
- 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
- * @throws IOException if an IO error occurs when writing to key file.
- */
- private void export() throws CardException, IOException {
- byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
-
- List<Response> sent = new LinkedList<>();
- sent.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send());
- sent.add(new Command.Clear(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
- sent.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
-
- // Cofactor generally isn't set on the default curve parameters on cards,
- // since its not necessary for ECDH, only ECDHC which not many cards implement
- // TODO: check if its assumend to be == 1?
- short domainAll = cfg.primeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
- short domain = (short) (domainAll ^ EC_Consts.PARAMETER_K);
- Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domainAll).send();
- if (!export.successful()) {
- export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
- }
- sent.add(export);
-
- for (Response r : sent) {
- respWriter.outputResponse(r);
- }
-
- EC_Params exported = new EC_Params(domain, export.getParams());
-
- FileOutputStream out = new FileOutputStream(cfg.output);
- exported.writeCSV(out);
- out.close();
- }
-
- /**
- * Generates EC keyPairs and outputs them to output file.
- *
- * @throws CardException if APDU transmission fails
- * @throws IOException if an IO error occurs when writing to key file.
- */
- 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);
-
- FileWriter keysFile = new FileWriter(cfg.output);
- keysFile.write("index;time;pubW;privS\n");
-
- int generated = 0;
- int retry = 0;
- while (generated < cfg.generateAmount || cfg.generateAmount == 0) {
- if ((cfg.fresh || generated == 0) && curve != null) {
- Response fresh = curve.send();
- respWriter.outputResponse(fresh);
- }
-
- Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
- Response.Generate response = generate.send();
- long elapsed = response.getDuration();
-
- Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
-
- if (!response.successful() || !export.successful()) {
- if (retry < 10) {
- retry++;
- continue;
- } else {
- System.err.println("Keys could not be generated.");
- break;
- }
- }
- 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 line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv);
- keysFile.write(line);
- keysFile.flush();
- generated++;
- }
- Response cleanup = new Command.Cleanup(cardManager).send();
- respWriter.outputResponse(cleanup);
-
- keysFile.close();
- }
-
- /**
- * Tests Elliptic curve support for a given curve/curves.
- *
- * @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;
-
- switch (cfg.testSuite) {
- case "default":
- suite = new DefaultSuite(dataStore, cfg);
- break;
- case "test-vectors":
- suite = new TestVectorSuite(dataStore, cfg);
- break;
- default:
- // These tests 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.");
- if (!cfg.yes) {
- System.out.print("Do you want to proceed? (y/n): ");
- Scanner in = new Scanner(System.in);
- String confirmation = in.nextLine().toLowerCase();
- if (!Arrays.asList("yes", "y").contains(confirmation)) {
- return;
- }
- in.close();
- }
-
-
- switch (cfg.testSuite) {
- case "wrong":
- suite = new WrongCurvesSuite(dataStore, cfg);
- break;
- case "composite":
- suite = new CompositeCurvesSuite(dataStore, cfg);
- break;
- case "invalid":
- suite = new InvalidCurvesSuite(dataStore, cfg);
- break;
- default:
- System.err.println("Unknown test suite.");
- return;
- }
- break;
- }
-
- TestRunner runner = new TestRunner(suite, testWriter);
- suite.setup(cardManager);
- runner.run();
- }
-
- /**
- * Performs ECDH key exchange.
- *
- * @throws CardException if APDU transmission fails
- * @throws IOException if an IO error occurs when writing to key file.
- */
- 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.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass);
- if (curve != null)
- prepare.add(curve.send());
-
- for (Response r : prepare) {
- respWriter.outputResponse(r);
- }
-
- byte pubkey = (cfg.anyPublicKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL;
- byte privkey = (cfg.anyPrivateKey || cfg.anyKey) ? ECTesterApplet.KEYPAIR_REMOTE : ECTesterApplet.KEYPAIR_LOCAL;
-
- 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));
- }
-
- FileWriter out = null;
- if (cfg.output != null) {
- out = new FileWriter(cfg.output);
- out.write("index;time;secret\n");
- }
-
- int retry = 0;
- int done = 0;
- while (done < cfg.ECDHCount) {
- 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();
- ecdh.add(perform);
- for (Response r : ecdh) {
- respWriter.outputResponse(r);
- }
-
- if (!perform.successful() || !perform.hasSecret()) {
- if (retry < 10) {
- ++retry;
- continue;
- } else {
- System.err.println("Couldn't obtain ECDH secret from card response.");
- break;
- }
- }
-
- if (out != null) {
- out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false)));
- }
-
- ++done;
- }
- Response cleanup = new Command.Cleanup(cardManager).send();
- respWriter.outputResponse(cleanup);
-
- if (out != null)
- out.close();
- }
-
- /**
- * Performs ECDSA signature, on random or provided data.
- *
- * @throws CardException if APDU transmission fails
- * @throws IOException if an IO error occurs when writing to key file.
- */
- private void ecdsa() throws CardException, IOException {
- //read file, if asked to sign
- byte[] data = null;
- if (cfg.input != null) {
- File in = new File(cfg.input);
- long len = in.length();
- if (len == 0) {
- throw new FileNotFoundException(cfg.input);
- }
- data = Files.readAllBytes(in.toPath());
- }
-
- Command generate;
- if (cfg.anyKeypart) {
- generate = Command.prepareKey(cardManager, dataStore, 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.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass);
- if (curve != null)
- prepare.add(curve.send());
-
- for (Response r : prepare) {
- respWriter.outputResponse(r);
- }
-
- FileWriter out = null;
- if (cfg.output != null) {
- out = new FileWriter(cfg.output);
- out.write("index;time;signature\n");
- }
-
- int retry = 0;
- int done = 0;
- while (done < cfg.ECDSACount) {
- List<Response> ecdsa = new LinkedList<>();
- ecdsa.add(generate.send());
-
- Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, data).send();
- ecdsa.add(perform);
- for (Response r : ecdsa) {
- respWriter.outputResponse(r);
- }
-
- if (!perform.successful() || !perform.hasSignature()) {
- if (retry < 10) {
- ++retry;
- continue;
- } else {
- System.err.println("Couldn't obtain ECDSA signature from card response.");
- break;
- }
- }
-
- if (out != null) {
- out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false)));
- }
-
- ++done;
- }
- Response cleanup = new Command.Cleanup(cardManager).send();
- respWriter.outputResponse(cleanup);
-
- if (out != null)
- out.close();
- }
-
- public static void main(String[] args) {
- ECTester app = new ECTester();
- app.run(args);
- }
-
- public static class Config {
-
- //Options
- public int 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;
- public boolean customCurve = false;
-
- public boolean anyPublicKey = false;
- public String namedPublicKey;
- public String publicKey;
-
- public boolean anyPrivateKey = false;
- public String namedPrivateKey;
- public String privateKey;
-
- public boolean anyKey = false;
- public String namedKey;
- public String key;
-
- public boolean anyKeypart = false;
-
- public String log;
-
- public boolean verbose = false;
- public String input;
- public String output;
- public boolean fresh = false;
- public boolean simulate = false;
- public boolean yes = false;
- public String format;
-
- //Action-related options
- public String listNamed;
- public String testSuite;
- public int generateAmount;
- public int ECDHCount;
- public byte ECDHKA;
- public int ECDSACount;
-
- /**
- * Reads and validates options, also sets defaults.
- *
- * @param cli cli object, with parsed args
- * @return whether the options are valid.
- */
- boolean readOptions(CommandLine cli) {
- bits = Integer.parseInt(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");
- curveFile = cli.getOptionValue("curve");
-
- namedPublicKey = cli.getOptionValue("named-public");
- publicKey = cli.getOptionValue("public");
- anyPublicKey = (publicKey != null) || (namedPublicKey != null);
-
- namedPrivateKey = cli.getOptionValue("named-private");
- privateKey = cli.getOptionValue("private");
- anyPrivateKey = (privateKey != null) || (namedPrivateKey != null);
-
- namedKey = cli.getOptionValue("named-key");
- key = cli.getOptionValue("key");
- anyKey = (key != null) || (namedKey != null);
- anyKeypart = anyKey || anyPublicKey || anyPrivateKey;
-
- if (cli.hasOption("log")) {
- log = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000));
- }
-
- verbose = cli.hasOption("verbose");
- input = cli.getOptionValue("input");
- output = cli.getOptionValue("output");
- fresh = cli.hasOption("fresh");
- simulate = cli.hasOption("simulate");
- yes = cli.hasOption("yes");
-
- if (cli.hasOption("list-named")) {
- listNamed = cli.getOptionValue("list-named");
- return true;
- }
-
- format = cli.getOptionValue("format", "text");
- String formats[] = new String[]{"text", "xml", "yaml", "yml"};
- if (!Arrays.asList(formats).contains(format)) {
- System.err.println("Wrong output format " + format + ". Should be one of " + Arrays.toString(formats));
- return false;
- }
-
- if ((key != null || namedKey != null) && (anyPublicKey || anyPrivateKey)) {
- System.err.print("Can only specify the whole key with --key/--named-key or pubkey and privkey with --public/--named-public and --private/--named-private.");
- return false;
- }
- if (bits < 0) {
- System.err.println("Bit-size must not be negative.");
- return false;
- }
- if (bits == 0 && !all) {
- System.err.println("You must specify either bit-size with -b or all bit-sizes with -a.");
- return false;
- }
-
- if (key != null && namedKey != null || publicKey != null && namedPublicKey != null || privateKey != null && namedPrivateKey != null) {
- System.err.println("You cannot specify both a named key and a key file.");
- return false;
- }
-
- if (cli.hasOption("export")) {
- if (primeField == binaryField) {
- System.err.print("Need to specify field with -fp or -f2m. (not both)");
- return false;
- }
- if (anyKeypart) {
- System.err.println("Keys should not be specified when exporting curve params.");
- return false;
- }
- if (namedCurve != null || customCurve || curveFile != null) {
- System.err.println("Specifying a curve for curve export makes no sense.");
- return false;
- }
- if (output == null) {
- System.err.println("You have to specify an output file for curve parameter export.");
- return false;
- }
- if (all) {
- 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)");
- return false;
- }
- if (anyKeypart) {
- System.err.println("Keys should not be specified when generating keys.");
- return false;
- }
- if (output == null) {
- System.err.println("You have to specify an output file for the key generation process.");
- return false;
- }
- if (all) {
- System.err.println("You have to specify curve bit-size with -b");
- return false;
- }
-
- generateAmount = Integer.parseInt(cli.getOptionValue("generate", "0"));
- if (generateAmount < 0) {
- System.err.println("Amount of keys generated cant be negative.");
- return false;
- }
- } else if (cli.hasOption("test")) {
- if (!(binaryField || primeField)) {
- binaryField = true;
- primeField = true;
- }
-
- testSuite = cli.getOptionValue("test", "default").toLowerCase();
- String[] tests = new String[]{"default", "composite", "invalid", "test-vectors", "wrong"};
- 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")) {
- if (primeField == binaryField) {
- System.err.print("Need to specify field with -fp or -f2m. (not both)");
- return false;
- }
- if (all) {
- System.err.println("You have to specify curve bit-size with -b");
- 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) {
- System.err.println("ECDH count cannot be <= 0.");
- return false;
- }
-
- } else if (cli.hasOption("ecdsa")) {
- if (primeField == binaryField) {
- System.err.print("Need to specify field with -fp or -f2m. (but not both)");
- return false;
- }
- if (all) {
- System.err.println("You have to specify curve bit-size with -b");
- return false;
- }
-
- if ((anyPublicKey) != (anyPrivateKey) && !anyKey) {
- System.err.println("You cannot only specify a part of a keypair.");
- return false;
- }
-
- ECDSACount = Integer.parseInt(cli.getOptionValue("ecdsa", "1"));
- if (ECDSACount <= 0) {
- System.err.println("ECDSA count cannot be <= 0.");
- return false;
- }
- }
- return true;
- }
- }
-}