From 7758239163e6c81f985fa4e33ad1c0cb57627f0e Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 15 Nov 2017 01:00:13 +0100 Subject: Add Tree-like CLI parsing utilities. --- src/cz/crcs/ectester/common/cli/TreeParser.java | 75 +++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/cz/crcs/ectester/common/cli/TreeParser.java (limited to 'src/cz/crcs/ectester/common/cli/TreeParser.java') diff --git a/src/cz/crcs/ectester/common/cli/TreeParser.java b/src/cz/crcs/ectester/common/cli/TreeParser.java new file mode 100644 index 0000000..079760e --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/TreeParser.java @@ -0,0 +1,75 @@ +package cz.crcs.ectester.common.cli; + +import org.apache.commons.cli.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; +import java.util.Properties; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TreeParser implements CommandLineParser { + private Map parsers; + private boolean required; + + public TreeParser(Map parsers, boolean required) { + this.parsers = parsers; + this.required = required; + } + + public Map getParsers() { + return Collections.unmodifiableMap(parsers); + } + + public boolean isRequired() { + return required; + } + + @Override + public CommandLine parse(Options options, String[] arguments) throws ParseException { + return this.parse(options, arguments, null); + } + + public CommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException { + return this.parse(options, arguments, properties, false); + } + + @Override + public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException { + return this.parse(options, arguments, null, stopAtNonOption); + } + + public CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption) throws ParseException { + DefaultParser thisParser = new DefaultParser(); + CommandLine cli = thisParser.parse(options, arguments, properties, true); + + CommandLine subCli = null; + String[] args = cli.getArgs(); + String sub = null; + if (args.length != 0) { + sub = args[0]; + ParserOptions subparser = parsers.get(sub); + if (subparser != null) { + String[] remainingArgs = new String[args.length - 1]; + System.arraycopy(args, 1, remainingArgs, 0, args.length - 1); + subCli = subparser.getParser().parse(subparser.getOptions(), remainingArgs, true); + } + } else { + if (required) { + throw new MissingOptionException(new ArrayList(parsers.keySet())); + } + } + if (subCli instanceof TreeCommandLine) { + TreeCommandLine subTreeCli = (TreeCommandLine) subCli; + subTreeCli.setName(sub); + return new TreeCommandLine(cli, subTreeCli); + } else if (subCli != null) { + TreeCommandLine subTreeCli = new TreeCommandLine(sub, subCli, null); + return new TreeCommandLine(cli, subTreeCli); + } else { + return new TreeCommandLine(cli, null); + } + } +} -- cgit v1.2.3-70-g09d2 From 9da5f6ee8db4138b13af6d1d7bef279ed107288d Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 15 Nov 2017 02:31:05 +0100 Subject: Add prefix handling of CLI actions. --- src/cz/crcs/ectester/common/cli/TreeParser.java | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src/cz/crcs/ectester/common/cli/TreeParser.java') diff --git a/src/cz/crcs/ectester/common/cli/TreeParser.java b/src/cz/crcs/ectester/common/cli/TreeParser.java index 079760e..8e7edb4 100644 --- a/src/cz/crcs/ectester/common/cli/TreeParser.java +++ b/src/cz/crcs/ectester/common/cli/TreeParser.java @@ -2,10 +2,7 @@ package cz.crcs.ectester.common.cli; import org.apache.commons.cli.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Map; -import java.util.Properties; +import java.util.*; /** * @author Jan Jancar johny@neuromancer.sk @@ -50,11 +47,27 @@ public class TreeParser implements CommandLineParser { String sub = null; if (args.length != 0) { sub = args[0]; - ParserOptions subparser = parsers.get(sub); - if (subparser != null) { + + List matches = new LinkedList<>(); + String finalSub = sub; + for (Map.Entry entry : parsers.entrySet()) { + if (entry.getKey().equalsIgnoreCase(finalSub)) { + matches.clear(); + matches.add(finalSub); + break; + } else if (entry.getKey().startsWith(finalSub)) { + matches.add(entry.getKey()); + } + } + + if (matches.size() == 1) { + sub = matches.get(0); + ParserOptions subparser = parsers.get(sub); String[] remainingArgs = new String[args.length - 1]; System.arraycopy(args, 1, remainingArgs, 0, args.length - 1); subCli = subparser.getParser().parse(subparser.getOptions(), remainingArgs, true); + } else if (matches.size() > 1) { + throw new UnrecognizedOptionException("Ambiguous option: " + sub + ", couldn't match. Partially matches: " + String.join(",", matches.toArray(new String[0])) + ".", sub); } } else { if (required) { -- cgit v1.2.3-70-g09d2 From fa6cea35cb6899f802d24951bf5e12639a251eb6 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 18 Nov 2017 15:16:05 +0100 Subject: Finish tree parsing of CLI args. --- src/cz/crcs/ectester/common/cli/Argument.java | 29 +++++ src/cz/crcs/ectester/common/cli/CLITools.java | 52 ++++++--- .../crcs/ectester/common/cli/TreeCommandLine.java | 23 ++++ src/cz/crcs/ectester/common/cli/TreeParser.java | 20 +++- .../ectester/standalone/ECTesterStandalone.java | 129 +++++++++++++-------- 5 files changed, 185 insertions(+), 68 deletions(-) create mode 100644 src/cz/crcs/ectester/common/cli/Argument.java (limited to 'src/cz/crcs/ectester/common/cli/TreeParser.java') diff --git a/src/cz/crcs/ectester/common/cli/Argument.java b/src/cz/crcs/ectester/common/cli/Argument.java new file mode 100644 index 0000000..e9b6688 --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/Argument.java @@ -0,0 +1,29 @@ +package cz.crcs.ectester.common.cli; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class Argument { + private String name; + private String desc; + private boolean required; + + public Argument(String name, String desc, boolean isRequired) { + this.name = name; + this.desc = desc; + this.required = isRequired; + } + + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public boolean isRequired() { + return required; + } +} diff --git a/src/cz/crcs/ectester/common/cli/CLITools.java b/src/cz/crcs/ectester/common/cli/CLITools.java index 1b73207..77b3794 100644 --- a/src/cz/crcs/ectester/common/cli/CLITools.java +++ b/src/cz/crcs/ectester/common/cli/CLITools.java @@ -25,14 +25,20 @@ public class CLITools { help.printHelp(prog, header, options, footer, usage); } - private static void help(HelpFormatter help, PrintWriter pw, CommandLineParser cli, int depth) { + private static void help(HelpFormatter help, PrintWriter pw, CommandLineParser cli, Options opts, int depth) { + if (opts.getOptions().size() > 0) { + help.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, opts, HelpFormatter.DEFAULT_LEFT_PAD + depth, HelpFormatter.DEFAULT_DESC_PAD); + } if (cli instanceof TreeParser) { TreeParser tp = (TreeParser) cli; + for (Argument arg : tp.getArgs()) { + String argname = arg.isRequired() ? "<" + arg.getName() + ">" : "[" + arg.getName() + "]"; + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + (depth + 1) + "s" + argname + " " + arg.getDesc(), " ")); + } tp.getParsers().forEach((key, value) -> { - help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + String.valueOf(depth) + "s" + key + ":", " ")); - help.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, value.getOptions(), HelpFormatter.DEFAULT_LEFT_PAD + depth, HelpFormatter.DEFAULT_DESC_PAD); pw.println(); - CLITools.help(help, pw, value.getParser(), depth + 1); + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + depth + "s" + key + ":", " ")); + CLITools.help(help, pw, value.getParser(), value.getOptions(), depth + 1); }); } } @@ -41,22 +47,37 @@ public class CLITools { StringWriter sw = new StringWriter(); PrintWriter upw = new PrintWriter(sw); help.printUsage(upw, HelpFormatter.DEFAULT_WIDTH, "", opts); - upw.print(" "); if (cli instanceof TreeParser) { + upw.print(" "); TreeParser tp = (TreeParser) cli; - if (!tp.isRequired()) { + String[] keys = tp.getParsers().keySet().toArray(new String[tp.getParsers().size()]); + if (keys.length > 0 && !tp.isRequired()) { upw.print("[ "); } - tp.getParsers().forEach((key, value) -> { - upw.print("( " + key + " "); + + for (int i = 0; i < keys.length; ++i) { + String key = keys[i]; + ParserOptions value = tp.getParsers().get(key); + upw.print("(" + key); usage(help, upw, value.getParser(), value.getOptions()); upw.print(")"); - }); - if (!tp.isRequired()) { + if (i != keys.length - 1) { + upw.print(" | "); + } + } + Argument[] args = tp.getArgs().toArray(new Argument[tp.getArgs().size()]); + String[] argss = new String[tp.getArgs().size()]; + for (int i = 0; i < args.length; ++i) { + Argument arg = args[i]; + argss[i] = arg.isRequired() ? "<" + arg.getName() + ">" : "[" + arg.getName() + "]"; + } + upw.print(String.join(" ", argss)); + + if (keys.length > 0 && !tp.isRequired()) { upw.print(" ]"); } } - pw.println(sw.toString().substring(8).replace("\n", "")); + pw.println(sw.toString().replaceAll("usage:( )?", "").replace("\n", "")); } /** @@ -67,18 +88,17 @@ public class CLITools { help.setOptionComparator(null); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, header); if (printUsage) { StringWriter uw = new StringWriter(); PrintWriter upw = new PrintWriter(uw); usage(help, upw, baseParser, baseOpts); - pw.print(prog + " usage: "); + pw.print("usage: " + prog); help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, uw.toString()); upw.close(); + pw.println(); } - help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, header); - help.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, baseOpts, HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD); - pw.println(); - help(help, pw, baseParser, 1); + help(help, pw, baseParser, baseOpts, 1); help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, footer); System.out.println(sw.toString()); } diff --git a/src/cz/crcs/ectester/common/cli/TreeCommandLine.java b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java index ef6079e..e0927fa 100644 --- a/src/cz/crcs/ectester/common/cli/TreeCommandLine.java +++ b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java @@ -5,6 +5,8 @@ import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import java.util.Iterator; +import java.util.List; +import java.util.Objects; import java.util.Properties; import java.util.function.BiFunction; @@ -45,6 +47,10 @@ public class TreeCommandLine extends CommandLine { return next; } + public boolean isNext(String next) { + return Objects.equals(getNextName(), next); + } + public CommandLine getThis() { return cli; } @@ -131,4 +137,21 @@ public class TreeCommandLine extends CommandLine { public Option[] getOptions() { return cli.getOptions(); } + + public String getArg(int index) { + if (index < 0 || index >= cli.getArgs().length) { + return null; + } + return cli.getArgs()[index]; + } + + @Override + public String[] getArgs() { + return cli.getArgs(); + } + + @Override + public List getArgList() { + return cli.getArgList(); + } } diff --git a/src/cz/crcs/ectester/common/cli/TreeParser.java b/src/cz/crcs/ectester/common/cli/TreeParser.java index 8e7edb4..9b197a5 100644 --- a/src/cz/crcs/ectester/common/cli/TreeParser.java +++ b/src/cz/crcs/ectester/common/cli/TreeParser.java @@ -10,12 +10,18 @@ import java.util.*; public class TreeParser implements CommandLineParser { private Map parsers; private boolean required; + private List args = Collections.emptyList(); public TreeParser(Map parsers, boolean required) { this.parsers = parsers; this.required = required; } + public TreeParser(Map parsers, boolean required, List args) { + this(parsers, required); + this.args = args; + } + public Map getParsers() { return Collections.unmodifiableMap(parsers); } @@ -24,21 +30,25 @@ public class TreeParser implements CommandLineParser { return required; } + public List getArgs() { + return Collections.unmodifiableList(args); + } + @Override - public CommandLine parse(Options options, String[] arguments) throws ParseException { + public TreeCommandLine parse(Options options, String[] arguments) throws ParseException { return this.parse(options, arguments, null); } - public CommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException { + public TreeCommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException { return this.parse(options, arguments, properties, false); } @Override - public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException { + public TreeCommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException { return this.parse(options, arguments, null, stopAtNonOption); } - public CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption) throws ParseException { + public TreeCommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption) throws ParseException { DefaultParser thisParser = new DefaultParser(); CommandLine cli = thisParser.parse(options, arguments, properties, true); @@ -67,7 +77,7 @@ public class TreeParser implements CommandLineParser { System.arraycopy(args, 1, remainingArgs, 0, args.length - 1); subCli = subparser.getParser().parse(subparser.getOptions(), remainingArgs, true); } else if (matches.size() > 1) { - throw new UnrecognizedOptionException("Ambiguous option: " + sub + ", couldn't match. Partially matches: " + String.join(",", matches.toArray(new String[0])) + ".", sub); + throw new AmbiguousOptionException(sub, matches); } } else { if (required) { diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 99253cc..3736e12 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -1,6 +1,6 @@ package cz.crcs.ectester.standalone; -import cz.crcs.ectester.common.cli.CLITools; +import cz.crcs.ectester.common.cli.*; import cz.crcs.ectester.common.test.Result; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; @@ -8,13 +8,17 @@ import cz.crcs.ectester.standalone.libs.BouncyCastleLib; import cz.crcs.ectester.standalone.libs.ECLibrary; import cz.crcs.ectester.standalone.libs.JavaECLibrary; import cz.crcs.ectester.standalone.libs.SunECLib; -import org.apache.commons.cli.*; +import cz.crcs.ectester.standalone.test.KeyGenerationTest; +import cz.crcs.ectester.standalone.test.KeyGenerationTestable; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; import java.io.IOException; -import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; +import java.util.*; /** * Standalone part of ECTester, a tool for testing Elliptic curve implementations in software libraries. @@ -29,6 +33,7 @@ public class ECTesterStandalone { private Config cfg; private Options opts = new Options(); + private TreeParser optParser; private static final String VERSION = "v0.1.0"; private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility."; private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; @@ -37,10 +42,10 @@ public class ECTesterStandalone { private void run(String[] args) { try { - CommandLine cli = parseArgs(args); + TreeCommandLine cli = parseArgs(args); if (cli.hasOption("help")) { - CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, CLI_FOOTER, true); + CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, optParser, CLI_FOOTER, true); return; } else if (cli.hasOption("version")) { CLITools.version(DESCRIPTION, LICENSE); @@ -56,30 +61,23 @@ public class ECTesterStandalone { } for (ECLibrary lib : libs) { - if (lib instanceof JavaECLibrary) { - JavaECLibrary jlib = (JavaECLibrary) lib; - lib.initialize(); - lib.getECKAs(); - lib.getECSigs(); - for (KeyPairGeneratorIdent ident : lib.getKPGs()) { - try { - KeyPairGenerator kpg = ident.getInstance(jlib.getProvider()); - kpg.initialize(192); - KeyPair kp = kpg.genKeyPair(); - System.out.println(kp); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - } - } - + lib.initialize(); } - System.out.println(Arrays.toString(libs)); - if (cli.hasOption("generate")) { - generate(); - } else if (cli.hasOption("list-libs")) { + if (cli.isNext("list-libs")) { listLibraries(); + } else if (cli.isNext("list-data")) { + CLITools.listNamed(dataStore, cli.getNext().getArg(0)); + } else if (cli.isNext("ecdh")) { + + } else if (cli.isNext("ecdsa")) { + + } else if (cli.isNext("generate")) { + generate(); + } else if (cli.isNext("test")) { + + } else if (cli.isNext("export")) { + } } catch (ParseException | IOException ex) { @@ -87,32 +85,69 @@ public class ECTesterStandalone { } } - private CommandLine parseArgs(String[] args) throws ParseException { - 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("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()); - 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("ls").longOpt("list-libs").desc("List supported libraries.").build()); - opts.addOptionGroup(actions); - - CommandLineParser parser = new DefaultParser(); - return parser.parse(opts, args); + private TreeCommandLine parseArgs(String[] args) throws ParseException { + Map actions = new TreeMap<>(); + + Options testOpts = new Options(); + ParserOptions test = new ParserOptions(new DefaultParser(), testOpts); + actions.put("test", test); + + Options ecdhOpts = new Options(); + ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); + ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts); + actions.put("ecdh", ecdh); + + Options ecdsaOpts = new Options(); + ecdsaOpts.addOption(Option.builder("t").longOpt("type").desc("Set Signature object [type].").hasArg().argName("type").optionalArg(false).build()); + ParserOptions ecdsa = new ParserOptions(new DefaultParser(), ecdsaOpts); + actions.put("ecdsa", ecdsa); + + Options generateOpts = new Options(); + generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build()); + ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts); + actions.put("generate", generate); + + Options exportOpts = new Options(); + ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts); + actions.put("export", export); + + Options listDataOpts = new Options(); + List listDataArgs = new LinkedList<>(); + listDataArgs.add(new Argument("what", "what to list.", false)); + ParserOptions listData = new ParserOptions(new TreeParser(Collections.emptyMap(), false, listDataArgs), listDataOpts); + actions.put("list-data", listData); + + Options listLibsOpts = new Options(); + ParserOptions listLibs = new ParserOptions(new DefaultParser(), listLibsOpts); + actions.put("list-libs", listLibs); + + optParser = new TreeParser(actions, false); + + opts.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); + opts.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); + + return optParser.parse(opts, args); } /** * */ private void generate() { - EC_Curve curve = dataStore.getObject(EC_Curve.class, "secg/secp192r1"); - byte[] fp = curve.getParam(EC_Consts.PARAMETER_FP)[0]; - + for (ECLibrary lib : libs) { + if (lib instanceof JavaECLibrary) { + JavaECLibrary jlib = (JavaECLibrary) lib; + for (KeyPairGeneratorIdent ident : lib.getKPGs()) { + try { + KeyPairGenerator kpg = ident.getInstance(jlib.getProvider()); + KeyGenerationTestable kgt = new KeyGenerationTestable(kpg, 192); + KeyGenerationTest kt = KeyGenerationTest.expect(kgt, Result.ExpectedValue.SUCCESS); + System.out.println(kt); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + } + } } /** -- cgit v1.2.3-70-g09d2 From 0fdfe31112924f51ca503c0ec0fff62ec20403c1 Mon Sep 17 00:00:00 2001 From: J08nY Date: Thu, 23 Nov 2017 01:32:41 +0100 Subject: Sketch out KeyPairGeneration in standalone. --- src/cz/crcs/ectester/common/cli/ParserOptions.java | 13 +++++ .../crcs/ectester/common/cli/TreeCommandLine.java | 27 ++++++++- src/cz/crcs/ectester/common/cli/TreeParser.java | 32 ++++++++-- .../ectester/standalone/ECTesterStandalone.java | 68 ++++++++++++++++++---- src/cz/crcs/ectester/standalone/consts/Ident.java | 4 ++ 5 files changed, 124 insertions(+), 20 deletions(-) (limited to 'src/cz/crcs/ectester/common/cli/TreeParser.java') diff --git a/src/cz/crcs/ectester/common/cli/ParserOptions.java b/src/cz/crcs/ectester/common/cli/ParserOptions.java index 4216ce3..ee2097e 100644 --- a/src/cz/crcs/ectester/common/cli/ParserOptions.java +++ b/src/cz/crcs/ectester/common/cli/ParserOptions.java @@ -3,18 +3,27 @@ package cz.crcs.ectester.common.cli; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.Options; +import java.util.Collections; +import java.util.List; + /** * @author Jan Jancar johny@neuromancer.sk */ public class ParserOptions { private CommandLineParser parser; private Options options; + private List arguments; public ParserOptions(CommandLineParser parser, Options options) { this.parser = parser; this.options = options; } + public ParserOptions(CommandLineParser parser, Options options, List arguments) { + this(parser, options); + this.arguments = arguments; + } + public CommandLineParser getParser() { return parser; } @@ -22,4 +31,8 @@ public class ParserOptions { public Options getOptions() { return options; } + + public List getArguments() { + return Collections.unmodifiableList(arguments); + } } diff --git a/src/cz/crcs/ectester/common/cli/TreeCommandLine.java b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java index 82d1e15..39607dc 100644 --- a/src/cz/crcs/ectester/common/cli/TreeCommandLine.java +++ b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java @@ -3,6 +3,7 @@ package cz.crcs.ectester.common.cli; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; +import sun.reflect.generics.tree.Tree; import java.util.Iterator; import java.util.List; @@ -55,11 +56,21 @@ public class TreeCommandLine extends CommandLine { return cli; } + public int getDepth() { + if (next == null) { + return 0; + } + return next.getDepth() + 1; + } + private T getOption(String opt, BiFunction getter, T defaultValue) { if (opt.contains(".")) { String[] parts = opt.split("\\.", 2); if (next != null && parts[0].equals(next.getName())) { - return getter.apply(next, parts[1]); + T result = getter.apply(next, parts[1]); + if (result != null) + return result; + return defaultValue; } return defaultValue; } @@ -138,11 +149,21 @@ public class TreeCommandLine extends CommandLine { return cli.getOptions(); } + public boolean hasArg(int index) { + if (next != null) { + return next.hasArg(index); + } + return Math.abs(index) < cli.getArgs().length; + } + public String getArg(int index) { - if (index < 0 || index >= cli.getArgs().length) { + if (next != null) { + return next.getArg(index); + } + if (index >= cli.getArgs().length) { return null; } - return cli.getArgs()[index]; + return index < 0 ? cli.getArgs()[cli.getArgs().length + index] : cli.getArgs()[index]; } @Override diff --git a/src/cz/crcs/ectester/common/cli/TreeParser.java b/src/cz/crcs/ectester/common/cli/TreeParser.java index 9b197a5..77cce30 100644 --- a/src/cz/crcs/ectester/common/cli/TreeParser.java +++ b/src/cz/crcs/ectester/common/cli/TreeParser.java @@ -3,6 +3,7 @@ package cz.crcs.ectester.common.cli; import org.apache.commons.cli.*; import java.util.*; +import java.util.stream.Collectors; /** * @author Jan Jancar johny@neuromancer.sk @@ -53,10 +54,10 @@ public class TreeParser implements CommandLineParser { CommandLine cli = thisParser.parse(options, arguments, properties, true); CommandLine subCli = null; - String[] args = cli.getArgs(); + String[] cliArgs = cli.getArgs(); String sub = null; - if (args.length != 0) { - sub = args[0]; + if (cliArgs.length != 0) { + sub = cliArgs[0]; List matches = new LinkedList<>(); String finalSub = sub; @@ -73,8 +74,8 @@ public class TreeParser implements CommandLineParser { if (matches.size() == 1) { sub = matches.get(0); ParserOptions subparser = parsers.get(sub); - String[] remainingArgs = new String[args.length - 1]; - System.arraycopy(args, 1, remainingArgs, 0, args.length - 1); + String[] remainingArgs = new String[cliArgs.length - 1]; + System.arraycopy(cliArgs, 1, remainingArgs, 0, cliArgs.length - 1); subCli = subparser.getParser().parse(subparser.getOptions(), remainingArgs, true); } else if (matches.size() > 1) { throw new AmbiguousOptionException(sub, matches); @@ -84,14 +85,35 @@ public class TreeParser implements CommandLineParser { throw new MissingOptionException(new ArrayList(parsers.keySet())); } } + + long requiredArgs = args.stream().filter(Argument::isRequired).count(); + String reqArgs = String.join(" ", args.stream().filter(Argument::isRequired).map(Argument::getName).collect(Collectors.toList())); + if (subCli instanceof TreeCommandLine) { TreeCommandLine subTreeCli = (TreeCommandLine) subCli; + + TreeCommandLine lastCli = subTreeCli; + while (lastCli.getNext() != null) { + lastCli = lastCli.getNext(); + } + + if (lastCli.getArgs().length < requiredArgs) { + throw new MissingArgumentException("Not enough arguments: " + reqArgs); + } + subTreeCli.setName(sub); return new TreeCommandLine(cli, subTreeCli); } else if (subCli != null) { + if (subCli.getArgs().length < requiredArgs) { + throw new MissingArgumentException("Not enough arguments: " + reqArgs); + } + TreeCommandLine subTreeCli = new TreeCommandLine(sub, subCli, null); return new TreeCommandLine(cli, subTreeCli); } else { + if (cliArgs.length < requiredArgs) { + throw new MissingArgumentException("Not enough arguments: " + reqArgs); + } return new TreeCommandLine(cli, null); } } diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java index 3736e12..dc65856 100644 --- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -1,24 +1,26 @@ package cz.crcs.ectester.standalone; import cz.crcs.ectester.common.cli.*; -import cz.crcs.ectester.common.test.Result; import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; import cz.crcs.ectester.standalone.libs.BouncyCastleLib; import cz.crcs.ectester.standalone.libs.ECLibrary; import cz.crcs.ectester.standalone.libs.JavaECLibrary; import cz.crcs.ectester.standalone.libs.SunECLib; -import cz.crcs.ectester.standalone.test.KeyGenerationTest; -import cz.crcs.ectester.standalone.test.KeyGenerationTestable; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; +import sun.reflect.generics.tree.Tree; import java.io.IOException; +import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.stream.Collectors; /** * Standalone part of ECTester, a tool for testing Elliptic curve implementations in software libraries. @@ -30,10 +32,11 @@ public class ECTesterStandalone { private ECLibrary[] libs = new ECLibrary[]{new SunECLib(), new BouncyCastleLib()}; private EC_Store dataStore; - private Config cfg; + private Config cfg = new Config(); private Options opts = new Options(); private TreeParser optParser; + private TreeCommandLine cli; private static final String VERSION = "v0.1.0"; private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility."; private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda "; @@ -42,9 +45,9 @@ public class ECTesterStandalone { private void run(String[] args) { try { - TreeCommandLine cli = parseArgs(args); + cli = parseArgs(args); - if (cli.hasOption("help")) { + if (cli.hasOption("help") || cli.getNext() == null) { CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, optParser, CLI_FOOTER, true); return; } else if (cli.hasOption("version")) { @@ -52,7 +55,7 @@ public class ECTesterStandalone { return; } - cfg = new Config(); + cfg.readOptions(cli); dataStore = new EC_Store(); if (cli.hasOption("list-named")) { @@ -104,6 +107,8 @@ public class ECTesterStandalone { Options generateOpts = new Options(); generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build()); + generateOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPairGenerator object [type].").build()); + generateOpts.addOption(Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build()); ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts); actions.put("generate", generate); @@ -121,7 +126,9 @@ public class ECTesterStandalone { ParserOptions listLibs = new ParserOptions(new DefaultParser(), listLibsOpts); actions.put("list-libs", listLibs); - optParser = new TreeParser(actions, false); + List baseArgs = new LinkedList<>(); + baseArgs.add(new Argument("lib", "What library to use.", false)); + optParser = new TreeParser(actions, false, baseArgs); opts.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); opts.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); @@ -133,15 +140,35 @@ public class ECTesterStandalone { * */ private void generate() { + if (!cli.hasArg(0)) { + System.err.println("Missing library name argument."); + return; + } + String libraryName = cli.getArg(0); + + List matchedLibs = new LinkedList<>(); for (ECLibrary lib : libs) { + if (lib.name().toLowerCase().contains(libraryName.toLowerCase())) { + matchedLibs.add(lib); + } + } + if (matchedLibs.size() == 0) { + System.err.println("No library found."); + } else if (matchedLibs.size() > 1) { + System.err.println("Multiple matching libraries found: " + String.join(",", matchedLibs.stream().map(ECLibrary::name).collect(Collectors.toList()))); + } else { + ECLibrary lib = matchedLibs.get(0); if (lib instanceof JavaECLibrary) { JavaECLibrary jlib = (JavaECLibrary) lib; for (KeyPairGeneratorIdent ident : lib.getKPGs()) { + if (!ident.contains(cli.getOptionValue("generate.type", "EC"))) { + continue; + } try { KeyPairGenerator kpg = ident.getInstance(jlib.getProvider()); - KeyGenerationTestable kgt = new KeyGenerationTestable(kpg, 192); - KeyGenerationTest kt = KeyGenerationTest.expect(kgt, Result.ExpectedValue.SUCCESS); - System.out.println(kt); + kpg.initialize(Integer.parseInt(cli.getOptionValue("generate.bits", "256"))); + KeyPair kp = kpg.genKeyPair(); + System.out.println(kp.getPrivate()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } @@ -156,7 +183,19 @@ public class ECTesterStandalone { private void listLibraries() { for (ECLibrary lib : libs) { if (lib.isInitialized()) { - System.out.println(lib.name()); + System.out.println("\t- " + lib.name()); + Set kpgs = lib.getKPGs(); + if (!kpgs.isEmpty()) { + System.out.println("\t\t- KeyPairGenerators: " + String.join(",", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList()))); + } + Set eckas = lib.getECKAs(); + if (!eckas.isEmpty()) { + System.out.println("\t\t- KeyAgreements: " + String.join(",", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList()))); + } + Set sigs = lib.getECSigs(); + if (!eckas.isEmpty()) { + System.out.println("\t\t- Signatures: " + String.join(",", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList()))); + } } } } @@ -167,6 +206,11 @@ public class ECTesterStandalone { } public static class Config { + public ECLibrary selected; + boolean readOptions(TreeCommandLine cli) { + + return true; + } } } diff --git a/src/cz/crcs/ectester/standalone/consts/Ident.java b/src/cz/crcs/ectester/standalone/consts/Ident.java index eaea0e3..84cce2d 100644 --- a/src/cz/crcs/ectester/standalone/consts/Ident.java +++ b/src/cz/crcs/ectester/standalone/consts/Ident.java @@ -24,6 +24,10 @@ public abstract class Ident { return Collections.unmodifiableSet(idents); } + public boolean contains(String other) { + return name.equals(other) || idents.contains(other); + } + @Override public boolean equals(Object obj) { if (this == obj) { -- cgit v1.2.3-70-g09d2