diff options
Diffstat (limited to 'src/cz/crcs/ectester/reader/ECTester.java')
| -rw-r--r-- | src/cz/crcs/ectester/reader/ECTester.java | 856 |
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; - } - } -} |
