aboutsummaryrefslogtreecommitdiff
path: root/common/src/main/java
diff options
context:
space:
mode:
authorJán Jančár2024-03-25 20:13:02 +0100
committerGitHub2024-03-25 20:13:02 +0100
commitdc7bb975e1c230f1f0a1937c454b2b90817d18e9 (patch)
tree8b4e3437e489894afcead9a6466050f3611cb38d /common/src/main/java
parent64b95fa059295e1dc23371c849f2302c1c18f5b4 (diff)
parent591deaece718b7821385ff0069b44adac4e1baf3 (diff)
downloadECTester-dc7bb975e1c230f1f0a1937c454b2b90817d18e9.tar.gz
ECTester-dc7bb975e1c230f1f0a1937c454b2b90817d18e9.tar.zst
ECTester-dc7bb975e1c230f1f0a1937c454b2b90817d18e9.zip
Merge pull request #20 from crocs-muni/feat/gradle
Move to gradle build
Diffstat (limited to 'common/src/main/java')
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/cli/Argument.java29
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/cli/CLITools.java161
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/cli/Colors.java97
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/cli/ParserOptions.java35
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/cli/TreeCommandLine.java179
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/cli/TreeParser.java130
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldF2m.java67
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldFp.java43
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/CustomECParameterSpec.java47
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/CustomEllipticCurve.java60
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_Category.java110
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_Consts.java1403
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_Curve.java162
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_Data.java265
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_KAResult.java65
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_Key.java81
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_Keypair.java39
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_Params.java233
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/EC_SigResult.java75
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/RawECPrivateKey.java46
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/ec/RawECPublicKey.java46
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/output/BaseTextTestWriter.java149
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/output/BaseXMLTestWriter.java144
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java120
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/output/OutputLogger.java63
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/output/TeeOutputStream.java36
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/output/TeeTestWriter.java43
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/output/TestWriter.java38
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/BaseTestable.java44
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/CompoundTest.java214
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/Result.java106
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/SimpleTest.java38
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/Test.java83
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/TestCallback.java11
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/TestException.java15
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/TestSuite.java100
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/TestSuiteException.java14
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/test/Testable.java38
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/util/ByteUtil.java193
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/util/CardConsts.java65
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/util/CardUtil.java569
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/util/ECUtil.java467
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/util/FileUtil.java99
-rw-r--r--common/src/main/java/cz/crcs/ectester/common/util/Util.java28
-rw-r--r--common/src/main/java/cz/crcs/ectester/data/EC_Store.java404
45 files changed, 6454 insertions, 0 deletions
diff --git a/common/src/main/java/cz/crcs/ectester/common/cli/Argument.java b/common/src/main/java/cz/crcs/ectester/common/cli/Argument.java
new file mode 100644
index 0000000..e9b6688
--- /dev/null
+++ b/common/src/main/java/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/common/src/main/java/cz/crcs/ectester/common/cli/CLITools.java b/common/src/main/java/cz/crcs/ectester/common/cli/CLITools.java
new file mode 100644
index 0000000..82ab530
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/cli/CLITools.java
@@ -0,0 +1,161 @@
+package cz.crcs.ectester.common.cli;
+
+import cz.crcs.ectester.common.ec.EC_Category;
+import cz.crcs.ectester.common.ec.EC_Data;
+import cz.crcs.ectester.data.EC_Store;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CLITools {
+
+ /**
+ * Print help.
+ */
+ public static void help(String prog, String header, Options options, String footer, boolean usage) {
+ HelpFormatter help = new HelpFormatter();
+ help.setOptionComparator(null);
+ help.printHelp(Colors.bold(prog), header, options, footer, usage);
+ }
+
+ private static void help(HelpFormatter help, PrintWriter pw, String cmd, ParserOptions parser, int depth) {
+ String description = parser.getDescription() == null ? "" : " | " + parser.getDescription() + " |";
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + depth + "s" + cmd + ":" + description, " "));
+ CLITools.help(help, pw, parser.getParser(), parser.getOptions(), depth + 1);
+ }
+
+ 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) -> {
+ pw.println();
+ help(help, pw, key, value, depth);
+ });
+ }
+ }
+
+ private static void usage(HelpFormatter help, PrintWriter pw, CommandLineParser cli, Options opts) {
+ StringWriter sw = new StringWriter();
+ PrintWriter upw = new PrintWriter(sw);
+ help.printUsage(upw, HelpFormatter.DEFAULT_WIDTH, "", opts);
+ if (cli instanceof TreeParser) {
+ upw.print(" ");
+ TreeParser tp = (TreeParser) cli;
+ String[] keys = tp.getParsers().keySet().toArray(new String[tp.getParsers().size()]);
+ if (keys.length > 0 && !tp.isRequired()) {
+ upw.print("[ ");
+ }
+
+ 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 (i != keys.length - 1) {
+ upw.print(" | ");
+ }
+ }
+
+ if (keys.length > 0 && !tp.isRequired()) {
+ upw.print(" ]");
+ }
+
+ Argument[] args = tp.getArgs().toArray(new Argument[tp.getArgs().size()]);
+ if (args.length > 0) {
+ 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));
+ }
+ }
+ pw.println(sw.toString().replaceAll("usage:( )?", "").replace("\n", ""));
+ }
+
+ /**
+ * Print tree help.
+ */
+ public static void help(String prog, String header, Options baseOpts, TreeParser baseParser, String footer, boolean printUsage) {
+ HelpFormatter help = new HelpFormatter();
+ 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("usage: " + Colors.bold(prog));
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, uw.toString());
+ upw.close();
+ pw.println();
+ }
+ help(help, pw, baseParser, baseOpts, 1);
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, footer);
+ System.out.println(sw.toString());
+ }
+
+ public static void help(String header, TreeParser baseParser, String footer, String command) {
+ ParserOptions opts = baseParser.getParsers().get(command);
+ if (opts == null) {
+ System.err.println("Command not found: " + command);
+ return;
+ }
+ HelpFormatter help = new HelpFormatter();
+ help.setOptionComparator(null);
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, header);
+ help(help, pw, command, opts, 1);
+ help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, footer);
+ System.out.println(sw.toString());
+ }
+
+ /**
+ * Print version info.
+ */
+ public static void version(String description, String license) {
+ System.out.println(description);
+ System.out.println(license);
+ }
+
+ /**
+ * List categories and named curves.
+ */
+ public static void listNamed(EC_Store dataStore, String named) {
+ Map<String, EC_Category> categories = dataStore.getCategories();
+ if (named == null) {
+ // print all categories, briefly
+ for (EC_Category cat : categories.values()) {
+ System.out.println(cat);
+ }
+ } else if (categories.containsKey(named)) {
+ // print given category
+ System.out.println(categories.get(named));
+ } else {
+ // print given object
+ EC_Data object = dataStore.getObject(EC_Data.class, named);
+ if (object != null) {
+ System.out.println(object);
+ } else {
+ System.err.println("Named object " + named + " not found!");
+ }
+ }
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/cli/Colors.java b/common/src/main/java/cz/crcs/ectester/common/cli/Colors.java
new file mode 100644
index 0000000..7601088
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/cli/Colors.java
@@ -0,0 +1,97 @@
+package cz.crcs.ectester.common.cli;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author Diogo Nunes
+ * @author Jan Jancar johny@neuromancer.sk
+ * Adapted from https://github.com/dialex/JCDP/
+ */
+public class Colors {
+ public static boolean enabled = false;
+
+ public interface ANSIParam {
+ }
+
+ public enum Foreground implements ANSIParam {
+ BLACK("30"), RED("31"), GREEN("32"), YELLOW("33"), BLUE("34"), MAGENTA("35"), CYAN("36"), WHITE("37"), NONE("");
+ private final String code;
+
+ Foreground(String code) {
+ this.code = code;
+ }
+
+ @Override
+ public String toString() {
+ return code;
+ }
+ }
+
+ public enum Background implements ANSIParam {
+ BLACK("40"), RED("41"), GREEN("42"), YELLOW("43"), BLUE("44"), MAGENTA("45"), CYAN("46"), WHITE("47"), NONE("");
+ private final String code;
+
+ Background(String code) {
+ this.code = code;
+ }
+
+ @Override
+ public String toString() {
+ return code;
+ }
+ }
+
+ public enum Attribute implements ANSIParam {
+ CLEAR("0"), BOLD("1"), LIGHT("1"), DARK("2"), UNDERLINE("4"), REVERSE("7"), HIDDEN("8"), NONE("");
+ private final String code;
+
+ Attribute(String code) {
+ this.code = code;
+ }
+
+ @Override
+ public String toString() {
+ return code;
+ }
+ }
+
+ private static final String PREFIX = "\033[";
+ private static final String SEPARATOR = ";";
+ private static final String POSTFIX = "m";
+
+ public static String colored(String text, ANSIParam... params) {
+ if (!enabled) {
+ return text;
+ }
+ Optional<Foreground> fg = Arrays.stream(params).filter(Foreground.class::isInstance).map(Foreground.class::cast).findFirst();
+ Optional<Background> bg = Arrays.stream(params).filter(Background.class::isInstance).map(Background.class::cast).findFirst();
+ List<Attribute> attr = Arrays.stream(params).filter(Attribute.class::isInstance).distinct().map(Attribute.class::cast).collect(Collectors.toList());
+
+ List<ANSIParam> apply = new LinkedList<>();
+ apply.addAll(attr);
+ fg.ifPresent(apply::add);
+ bg.ifPresent(apply::add);
+ List<String> codes = apply.stream().map(Object::toString).collect(Collectors.toList());
+ return PREFIX + String.join(SEPARATOR, codes) + POSTFIX + text + PREFIX + Attribute.CLEAR + POSTFIX;
+ }
+
+ public static String error(String text) {
+ return colored(text, Foreground.RED, Attribute.BOLD);
+ }
+
+ public static String ok(String text) {
+ return colored(text, Foreground.GREEN, Attribute.BOLD);
+ }
+
+ public static String bold(String text) {
+ return colored(text, Attribute.BOLD);
+ }
+
+ public static String underline(String text) {
+ return colored(text, Attribute.UNDERLINE);
+ }
+} \ No newline at end of file
diff --git a/common/src/main/java/cz/crcs/ectester/common/cli/ParserOptions.java b/common/src/main/java/cz/crcs/ectester/common/cli/ParserOptions.java
new file mode 100644
index 0000000..7300cbb
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/cli/ParserOptions.java
@@ -0,0 +1,35 @@
+package cz.crcs.ectester.common.cli;
+
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.Options;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ParserOptions {
+ private CommandLineParser parser;
+ private Options options;
+ private String description;
+
+ public ParserOptions(CommandLineParser parser, Options options) {
+ this.parser = parser;
+ this.options = options;
+ }
+
+ public ParserOptions(CommandLineParser parser, Options options, String description) {
+ this(parser, options);
+ this.description = description;
+ }
+
+ public CommandLineParser getParser() {
+ return parser;
+ }
+
+ public Options getOptions() {
+ return options;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/cli/TreeCommandLine.java b/common/src/main/java/cz/crcs/ectester/common/cli/TreeCommandLine.java
new file mode 100644
index 0000000..d758b78
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/cli/TreeCommandLine.java
@@ -0,0 +1,179 @@
+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 java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.function.BiFunction;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public class TreeCommandLine extends CommandLine {
+ private String name = "";
+ private TreeCommandLine next;
+ private CommandLine cli;
+
+ public TreeCommandLine(CommandLine cli, TreeCommandLine next) {
+ this.cli = cli;
+ this.next = next;
+ }
+
+ public TreeCommandLine(String name, CommandLine cli, TreeCommandLine next) {
+ this(cli, next);
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getNextName() {
+ if (next != null) {
+ return next.getName();
+ }
+ return null;
+ }
+
+ public TreeCommandLine getNext() {
+ return next;
+ }
+
+ public boolean isNext(String next) {
+ return Objects.equals(getNextName(), next);
+ }
+
+ public CommandLine getThis() {
+ return cli;
+ }
+
+ public int getDepth() {
+ if (next == null) {
+ return 0;
+ }
+ return next.getDepth() + 1;
+ }
+
+ private <T> T getOption(String opt, BiFunction<CommandLine, String, T> getter, T defaultValue) {
+ if (opt.contains(".")) {
+ String[] parts = opt.split("\\.", 2);
+ if (next != null && parts[0].equals(next.getName())) {
+ T result = getter.apply(next, parts[1]);
+ if (result != null)
+ return result;
+ return defaultValue;
+ }
+ return defaultValue;
+ }
+ return getter.apply(cli, opt);
+ }
+
+ @Override
+ public boolean hasOption(String opt) {
+ return getOption(opt, CommandLine::hasOption, false);
+ }
+
+ @Override
+ public boolean hasOption(char opt) {
+ return cli.hasOption(opt);
+ }
+
+ @Override
+ public Object getParsedOptionValue(String opt) throws ParseException {
+ if (opt.contains(".")) {
+ String[] parts = opt.split("\\.", 2);
+ if (next != null && parts[0].equals(next.getName())) {
+ return next.getParsedOptionValue(parts[1]);
+ }
+ return null;
+ }
+ return cli.getParsedOptionValue(opt);
+ }
+
+ @Override
+ public Object getOptionObject(char opt) {
+ return cli.getOptionObject(opt);
+ }
+
+ @Override
+ public String getOptionValue(String opt) {
+ return getOption(opt, CommandLine::getOptionValue, null);
+ }
+
+ @Override
+ public String getOptionValue(char opt) {
+ return cli.getOptionValue(opt);
+ }
+
+ @Override
+ public String[] getOptionValues(String opt) {
+ return getOption(opt, CommandLine::getOptionValues, null);
+ }
+
+ @Override
+ public String[] getOptionValues(char opt) {
+ return cli.getOptionValues(opt);
+ }
+
+ @Override
+ public String getOptionValue(String opt, String defaultValue) {
+ return getOption(opt, CommandLine::getOptionValue, defaultValue);
+ }
+
+ @Override
+ public String getOptionValue(char opt, String defaultValue) {
+ return cli.getOptionValue(opt, defaultValue);
+ }
+
+ @Override
+ public Properties getOptionProperties(String opt) {
+ return getOption(opt, CommandLine::getOptionProperties, new Properties());
+ }
+
+ @Override
+ public Iterator<Option> iterator() {
+ return cli.iterator();
+ }
+
+ @Override
+ public Option[] getOptions() {
+ return cli.getOptions();
+ }
+
+ public boolean hasArg(int index) {
+ return getArg(index) != null;
+ }
+
+ public String getArg(int index) {
+ if (next != null) {
+ return next.getArg(index);
+ }
+ String[] args = cli.getArgs();
+ if (index >= args.length) {
+ return null;
+ }
+ if (index < 0 && -index > args.length) {
+ return null;
+ }
+ return index < 0 ? args[args.length + index] : args[index];
+ }
+
+ @Override
+ public String[] getArgs() {
+ return cli.getArgs();
+ }
+
+ @Override
+ public List<String> getArgList() {
+ return cli.getArgList();
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/cli/TreeParser.java b/common/src/main/java/cz/crcs/ectester/common/cli/TreeParser.java
new file mode 100644
index 0000000..657318d
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/cli/TreeParser.java
@@ -0,0 +1,130 @@
+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
+ */
+public class TreeParser implements CommandLineParser {
+ private Map<String, ParserOptions> parsers;
+ private boolean required;
+ private List<Argument> args = Collections.emptyList();
+
+ public TreeParser(Map<String, ParserOptions> parsers, boolean required) {
+ this.parsers = parsers;
+ this.required = required;
+ }
+
+ public TreeParser(Map<String, ParserOptions> parsers, boolean required, List<Argument> args) {
+ this(parsers, required);
+ this.args = args;
+ }
+
+ public Map<String, ParserOptions> getParsers() {
+ return Collections.unmodifiableMap(parsers);
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+
+ public List<Argument> getArgs() {
+ return Collections.unmodifiableList(args);
+ }
+
+ @Override
+ public TreeCommandLine parse(Options options, String[] arguments) throws ParseException {
+ return this.parse(options, arguments, null);
+ }
+
+ public TreeCommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException {
+ return this.parse(options, arguments, properties, false);
+ }
+
+ @Override
+ public TreeCommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
+ return this.parse(options, arguments, null, stopAtNonOption);
+ }
+
+ 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);
+
+ CommandLine subCli = null;
+ String[] cliArgs = cli.getArgs();
+ String sub = null;
+ if (cliArgs.length != 0) {
+ sub = cliArgs[0];
+
+ List<String> matches = new LinkedList<>();
+ String finalSub = sub;
+ for (Map.Entry<String, ParserOptions> 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[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);
+ }
+ } else {
+ if (required) {
+ throw new MissingOptionException(new ArrayList<>(parsers.keySet()));
+ }
+ }
+
+ int maxArgs = args.size();
+ 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);
+ }
+ //else if (lastCli.getArgs().length > maxArgs) {
+ // throw new MissingArgumentException("Too many arguments.");
+ //}
+
+ subTreeCli.setName(sub);
+ return new TreeCommandLine(cli, subTreeCli);
+ } else if (subCli != null) {
+ if (subCli.getArgs().length < requiredArgs) {
+ throw new MissingArgumentException("Not enough arguments: " + reqArgs);
+ } else if (subCli.getArgs().length > maxArgs) {
+ throw new MissingArgumentException("Too many arguments.");
+ }
+
+ TreeCommandLine subTreeCli = new TreeCommandLine(sub, subCli, null);
+ return new TreeCommandLine(cli, subTreeCli);
+ } else {
+ if (cliArgs.length < requiredArgs) {
+ throw new MissingArgumentException("Not enough arguments: " + reqArgs);
+ }
+ //else if (cliArgs.length > maxArgs) {
+ // throw new MissingArgumentException("Too many arguments.");
+ //}
+
+ return new TreeCommandLine(cli, null);
+ }
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldF2m.java b/common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldF2m.java
new file mode 100644
index 0000000..24ea5aa
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldF2m.java
@@ -0,0 +1,67 @@
+package cz.crcs.ectester.common.ec;
+
+import java.math.BigInteger;
+import java.security.spec.ECFieldF2m;
+import java.util.Arrays;
+
+/**
+ * @author David Hofman
+ */
+public class CustomECFieldF2m extends ECFieldF2m {
+ private int m;
+ private int[] ks;
+ private BigInteger rp;
+
+ public CustomECFieldF2m(int m, int[] ks) {
+ //feed the constructor of the superclass some default, valid data
+ //getters will return custom parameters instead
+ super(163, new int[] {3, 2, 1});
+ this.m = m;
+ this.ks = ks.clone();
+
+ //causes ArithmeticException if m < 0 or any element of ks < 0
+ this.rp = BigInteger.ONE;
+ this.rp = this.rp.setBit(m);
+ for(int i = 0; i < this.ks.length; ++i) {
+ this.rp = this.rp.setBit(this.ks[i]);
+ }
+ }
+
+ @Override
+ public int getFieldSize() {
+ return m;
+ }
+
+ @Override
+ public int getM() {
+ return m;
+ }
+
+ @Override
+ public int[] getMidTermsOfReductionPolynomial() {
+ return ks.clone();
+ }
+
+ @Override
+ public BigInteger getReductionPolynomial() {
+ return rp;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ } else if (!(o instanceof CustomECFieldF2m)) {
+ return false;
+ } else {
+ return m == ((CustomECFieldF2m) o).m && Arrays.equals(ks, ((CustomECFieldF2m) o).ks);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = m << 5;
+ hash += rp == null ? 0 : rp.hashCode();
+ return hash;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldFp.java b/common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldFp.java
new file mode 100644
index 0000000..eafcb72
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/CustomECFieldFp.java
@@ -0,0 +1,43 @@
+package cz.crcs.ectester.common.ec;
+
+import java.math.BigInteger;
+import java.security.spec.ECFieldFp;
+
+/**
+ * @author David Hofman
+ */
+public class CustomECFieldFp extends ECFieldFp {
+ private BigInteger p;
+
+ public CustomECFieldFp(BigInteger p) {
+ //feed the constructor of the superclass some default, valid parameter p
+ //getters will return custom (and possibly invalid) data
+ super(BigInteger.ONE);
+ this.p = p;
+ }
+
+
+ @Override
+ public int getFieldSize() {
+ return p.bitCount();
+ }
+
+ @Override
+ public BigInteger getP() {
+ return p;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ } else {
+ return o instanceof CustomECFieldFp && p.equals(((CustomECFieldFp) o).p);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return p.hashCode();
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/CustomECParameterSpec.java b/common/src/main/java/cz/crcs/ectester/common/ec/CustomECParameterSpec.java
new file mode 100644
index 0000000..cbc15e7
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/CustomECParameterSpec.java
@@ -0,0 +1,47 @@
+package cz.crcs.ectester.common.ec;
+
+import java.math.BigInteger;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+/**
+ * @author David Hofman
+ */
+public class CustomECParameterSpec extends ECParameterSpec {
+ private EllipticCurve curve;
+ private ECPoint g;
+ private BigInteger n;
+ private int h;
+
+ public CustomECParameterSpec(EllipticCurve curve, ECPoint g, BigInteger n, int h) {
+ //feed the constructor of the superclass some default, valid data
+ //getters will return custom (and possibly invalid) parameters instead
+ super(new EllipticCurve(new ECFieldFp(BigInteger.ONE),BigInteger.ZERO,BigInteger.ZERO), new ECPoint(BigInteger.ZERO, BigInteger.ZERO), BigInteger.ONE, 1);
+ this.curve = curve;
+ this.g = g;
+ this.n = n;
+ this.h = h;
+ }
+
+ @Override
+ public EllipticCurve getCurve() {
+ return curve;
+ }
+
+ @Override
+ public ECPoint getGenerator() {
+ return g;
+ }
+
+ @Override
+ public BigInteger getOrder() {
+ return n;
+ }
+
+ @Override
+ public int getCofactor() {
+ return h;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/CustomEllipticCurve.java b/common/src/main/java/cz/crcs/ectester/common/ec/CustomEllipticCurve.java
new file mode 100644
index 0000000..489861c
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/CustomEllipticCurve.java
@@ -0,0 +1,60 @@
+package cz.crcs.ectester.common.ec;
+
+import java.math.BigInteger;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldFp;
+import java.security.spec.EllipticCurve;
+
+/**
+ * @author David Hofman
+ */
+public class CustomEllipticCurve extends EllipticCurve {
+ private ECField field;
+ private BigInteger a;
+ private BigInteger b;
+
+ public CustomEllipticCurve(ECField field, BigInteger a, BigInteger b) {
+ //feed the constructor of the superclass some default, valid EC parameters
+ //getters will return custom (and possibly invalid) data instead
+ super(new ECFieldFp(BigInteger.ONE), BigInteger.ZERO, BigInteger.ZERO);
+ this.field = field;
+ this.a = a;
+ this.b = b;
+
+ }
+
+ @Override
+ public BigInteger getA() {
+ return a;
+ }
+
+ @Override
+ public BigInteger getB() {
+ return b;
+ }
+
+ @Override
+ public ECField getField() {
+ return field;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ } else {
+ if (o instanceof CustomEllipticCurve) {
+ CustomEllipticCurve otherCurve = (CustomEllipticCurve) o;
+ if (field.equals(otherCurve.field) && a.equals(otherCurve.a) && b.equals(otherCurve.b)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return field.hashCode() << 6 + (a.hashCode() << 4) + (b.hashCode() << 2);
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_Category.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Category.java
new file mode 100644
index 0000000..154403e
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Category.java
@@ -0,0 +1,110 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.cli.Colors;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * A category of EC_Data objects, has a name, description and represents a directory in
+ * the cz.crcs.ectester.data package.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Category {
+
+ private String name;
+ private String directory;
+ private String desc;
+
+ private Map<String, EC_Data> objects;
+
+
+ public EC_Category(String name, String directory) {
+ this.name = name;
+ this.directory = directory;
+ }
+
+ public EC_Category(String name, String directory, String desc) {
+ this(name, directory);
+ this.desc = desc;
+ }
+
+ public EC_Category(String name, String directory, String desc, Map<String, EC_Data> objects) {
+ this(name, directory, desc);
+ this.objects = objects;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDirectory() {
+ return directory;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public Map<String, EC_Data> getObjects() {
+ return Collections.unmodifiableMap(objects);
+ }
+
+ public <T extends EC_Data> Map<String, T> getObjects(Class<T> cls) {
+ Map<String, T> objs = new TreeMap<>();
+ for (Map.Entry<String, EC_Data> entry : objects.entrySet()) {
+ if (cls.isInstance(entry.getValue())) {
+ objs.put(entry.getKey(), cls.cast(entry.getValue()));
+ }
+ }
+ return Collections.unmodifiableMap(objs);
+ }
+
+ public <T extends EC_Data> T getObject(Class<T> cls, String id) {
+ EC_Data obj = objects.get(id);
+ if (cls.isInstance(obj)) {
+ return cls.cast(obj);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder out = new StringBuilder();
+ out.append("\t- ").append(Colors.bold(name)).append((desc == null || desc.equals("")) ? "" : ": " + desc);
+ out.append(System.lineSeparator());
+
+ String[] headers = new String[]{"Curves", "Public keys", "Private keys", "KeyPairs", "Results(KA)", "Results(SIG)"};
+ Class<EC_Data>[] classes = new Class[]{EC_Curve.class, EC_Key.Public.class, EC_Key.Private.class, EC_Keypair.class, EC_KAResult.class, EC_SigResult.class};
+ for (int i = 0; i < headers.length; ++i) {
+ Map<String, EC_Data> data = getObjects(classes[i]);
+ int size = data.size();
+ if (size > 0) {
+ out.append(Colors.bold(String.format("\t\t%s: ", headers[i])));
+ List<EC_Data> sorted = new ArrayList<>(data.values());
+ Collections.sort(sorted);
+ for (EC_Data element : sorted) {
+ out.append(element.getId());
+ size--;
+ if (size > 0)
+ out.append(", ");
+ }
+ out.append(System.lineSeparator());
+ }
+ }
+ return out.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof EC_Category && Objects.equals(this.name, ((EC_Category) obj).name);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.name.hashCode() ^ this.directory.hashCode();
+ }
+
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_Consts.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Consts.java
new file mode 100644
index 0000000..86c30fa
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Consts.java
@@ -0,0 +1,1403 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.ByteUtil;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Consts {
+ private static byte[] EC_FP_P = null; //p
+ private static byte[] EC_A = null; //a
+ private static byte[] EC_B = null; //b
+ private static byte[] EC_G_X = null; //G[x,y]
+ private static byte[] EC_G_Y = null; //
+ private static byte[] EC_R = null; //n
+ private static short EC_K = 1; //h
+
+ private static byte[] EC_W_X = null; //Pubkey[x,y]
+ private static byte[] EC_W_Y = null;
+ private static byte[] EC_S = null; //Private
+
+ private static byte[] EC_F2M_F2M = null; //[short i1, short i2, short i3], f = x^m + x^i1 + x^i2 + x^i3 + 1
+
+ // EC domain parameter identifiers (bit flags)
+ public static final short PARAMETER_FP = 0x0001;
+ public static final short PARAMETER_F2M = 0x0002;
+
+ public static final short PARAMETER_A = 0x0004;
+ public static final short PARAMETER_B = 0x0008;
+ public static final short PARAMETER_G = 0x0010;
+ public static final short PARAMETER_R = 0x0020;
+ public static final short PARAMETER_K = 0x0040;
+ public static final short PARAMETER_W = 0x0080;
+ public static final short PARAMETER_S = 0x0100;
+
+ public static final short PARAMETERS_NONE = 0x0000;
+ /**
+ * FP,A,B,G,R,K
+ */
+ public static final short PARAMETERS_DOMAIN_FP = 0x007d;
+ /**
+ * F2M,A,B,G,R,K
+ */
+ public static final short PARAMETERS_DOMAIN_F2M = 0x007e;
+ /**
+ * W,S
+ */
+ public static final short PARAMETERS_KEYPAIR = 0x0180;
+ public static final short PARAMETERS_ALL = 0x01ff;
+
+ // EC key identifiers
+ public static final byte KEY_PUBLIC = 0x01;
+ public static final byte KEY_PRIVATE = 0x02;
+ public static final byte KEY_BOTH = KEY_PUBLIC | KEY_PRIVATE;
+
+ // secp112r1
+ public static final byte[] EC112_FP_P = new byte[]{
+ (byte) 0xdb, (byte) 0x7c, (byte) 0x2a, (byte) 0xbf,
+ (byte) 0x62, (byte) 0xe3, (byte) 0x5e, (byte) 0x66,
+ (byte) 0x80, (byte) 0x76, (byte) 0xbe, (byte) 0xad,
+ (byte) 0x20, (byte) 0x8b
+ };
+
+ public static final byte[] EC112_FP_A = new byte[]{
+ (byte) 0xdb, (byte) 0x7c, (byte) 0x2a, (byte) 0xbf,
+ (byte) 0x62, (byte) 0xe3, (byte) 0x5e, (byte) 0x66,
+ (byte) 0x80, (byte) 0x76, (byte) 0xbe, (byte) 0xad,
+ (byte) 0x20, (byte) 0x88
+ };
+
+ public static final byte[] EC112_FP_B = new byte[]{
+ (byte) 0x65, (byte) 0x9e, (byte) 0xf8, (byte) 0xba,
+ (byte) 0x04, (byte) 0x39, (byte) 0x16, (byte) 0xee,
+ (byte) 0xde, (byte) 0x89, (byte) 0x11, (byte) 0x70,
+ (byte) 0x2b, (byte) 0x22
+ };
+
+ public static final byte[] EC112_FP_G_X = new byte[]{
+ (byte) 0x09, (byte) 0x48, (byte) 0x72, (byte) 0x39,
+ (byte) 0x99, (byte) 0x5a, (byte) 0x5e, (byte) 0xe7,
+ (byte) 0x6b, (byte) 0x55, (byte) 0xf9, (byte) 0xc2,
+ (byte) 0xf0, (byte) 0x98
+ };
+
+ public static final byte[] EC112_FP_G_Y = new byte[]{
+ (byte) 0xa8, (byte) 0x9c, (byte) 0xe5, (byte) 0xaf,
+ (byte) 0x87, (byte) 0x24, (byte) 0xc0, (byte) 0xa2,
+ (byte) 0x3e, (byte) 0x0e, (byte) 0x0f, (byte) 0xf7,
+ (byte) 0x75, (byte) 0x00
+ };
+
+ public static final byte[] EC112_FP_R = new byte[]{
+ (byte) 0xdb, (byte) 0x7c, (byte) 0x2a, (byte) 0xbf,
+ (byte) 0x62, (byte) 0xe3, (byte) 0x5e, (byte) 0x76,
+ (byte) 0x28, (byte) 0xdf, (byte) 0xac, (byte) 0x65,
+ (byte) 0x61, (byte) 0xc5
+ };
+
+ public static final short EC112_FP_K = 1;
+
+
+ // secp128r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC128_FP_P = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFD,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+ };
+
+ public static final byte[] EC128_FP_A = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFD,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC
+ };
+
+ public static final byte[] EC128_FP_B = new byte[]{
+ (byte) 0xE8, (byte) 0x75, (byte) 0x79, (byte) 0xC1,
+ (byte) 0x10, (byte) 0x79, (byte) 0xF4, (byte) 0x3D,
+ (byte) 0xD8, (byte) 0x24, (byte) 0x99, (byte) 0x3C,
+ (byte) 0x2C, (byte) 0xEE, (byte) 0x5E, (byte) 0xD3
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC128_FP_G_X = new byte[]{
+ (byte) 0x16, (byte) 0x1F, (byte) 0xF7, (byte) 0x52,
+ (byte) 0x8B, (byte) 0x89, (byte) 0x9B, (byte) 0x2D,
+ (byte) 0x0C, (byte) 0x28, (byte) 0x60, (byte) 0x7C,
+ (byte) 0xA5, (byte) 0x2C, (byte) 0x5B, (byte) 0x86
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC128_FP_G_Y = new byte[]{
+ (byte) 0xCF, (byte) 0x5A, (byte) 0xC8, (byte) 0x39,
+ (byte) 0x5B, (byte) 0xAF, (byte) 0xEB, (byte) 0x13,
+ (byte) 0xC0, (byte) 0x2D, (byte) 0xA2, (byte) 0x92,
+ (byte) 0xDD, (byte) 0xED, (byte) 0x7A, (byte) 0x83
+ };
+ // Order of G
+ public static final byte[] EC128_FP_R = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x75, (byte) 0xA3, (byte) 0x0D, (byte) 0x1B,
+ (byte) 0x90, (byte) 0x38, (byte) 0xA1, (byte) 0x15
+ };
+ // cofactor of G
+ public static final short EC128_FP_K = 1;
+
+ // secp160r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC160_FP_P = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+ };
+
+ public static final byte[] EC160_FP_A = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC
+ };
+
+ public static final byte[] EC160_FP_B = new byte[]{
+ (byte) 0x1C, (byte) 0x97, (byte) 0xBE, (byte) 0xFC,
+ (byte) 0x54, (byte) 0xBD, (byte) 0x7A, (byte) 0x8B,
+ (byte) 0x65, (byte) 0xAC, (byte) 0xF8, (byte) 0x9F,
+ (byte) 0x81, (byte) 0xD4, (byte) 0xD4, (byte) 0xAD,
+ (byte) 0xC5, (byte) 0x65, (byte) 0xFA, (byte) 0x45
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC160_FP_G_X = new byte[]{
+ (byte) 0x4A, (byte) 0x96, (byte) 0xB5, (byte) 0x68,
+ (byte) 0x8E, (byte) 0xF5, (byte) 0x73, (byte) 0x28,
+ (byte) 0x46, (byte) 0x64, (byte) 0x69, (byte) 0x89,
+ (byte) 0x68, (byte) 0xC3, (byte) 0x8B, (byte) 0xB9,
+ (byte) 0x13, (byte) 0xCB, (byte) 0xFC, (byte) 0x82
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC160_FP_G_Y = new byte[]{
+ (byte) 0x23, (byte) 0xA6, (byte) 0x28, (byte) 0x55,
+ (byte) 0x31, (byte) 0x68, (byte) 0x94, (byte) 0x7D,
+ (byte) 0x59, (byte) 0xDC, (byte) 0xC9, (byte) 0x12,
+ (byte) 0x04, (byte) 0x23, (byte) 0x51, (byte) 0x37,
+ (byte) 0x7A, (byte) 0xC5, (byte) 0xFB, (byte) 0x32
+ };
+ // Order of G
+ public static final byte[] EC160_FP_R = new byte[]{
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0xF4, (byte) 0xC8,
+ (byte) 0xF9, (byte) 0x27, (byte) 0xAE, (byte) 0xD3,
+ (byte) 0xCA, (byte) 0x75, (byte) 0x22, (byte) 0x57
+ };
+ // cofactor of G
+ public static final short EC160_FP_K = 1;
+
+
+ // secp192r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC192_FP_P = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+ };
+ public static final byte[] EC192_FP_A = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC
+ };
+ public static final byte[] EC192_FP_B = new byte[]{
+ (byte) 0x64, (byte) 0x21, (byte) 0x05, (byte) 0x19,
+ (byte) 0xE5, (byte) 0x9C, (byte) 0x80, (byte) 0xE7,
+ (byte) 0x0F, (byte) 0xA7, (byte) 0xE9, (byte) 0xAB,
+ (byte) 0x72, (byte) 0x24, (byte) 0x30, (byte) 0x49,
+ (byte) 0xFE, (byte) 0xB8, (byte) 0xDE, (byte) 0xEC,
+ (byte) 0xC1, (byte) 0x46, (byte) 0xB9, (byte) 0xB1
+ };
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC192_FP_G_X = new byte[]{
+ (byte) 0x18, (byte) 0x8D, (byte) 0xA8, (byte) 0x0E,
+ (byte) 0xB0, (byte) 0x30, (byte) 0x90, (byte) 0xF6,
+ (byte) 0x7C, (byte) 0xBF, (byte) 0x20, (byte) 0xEB,
+ (byte) 0x43, (byte) 0xA1, (byte) 0x88, (byte) 0x00,
+ (byte) 0xF4, (byte) 0xFF, (byte) 0x0A, (byte) 0xFD,
+ (byte) 0x82, (byte) 0xFF, (byte) 0x10, (byte) 0x12
+ };
+ // second part of G uncompressed
+ public static final byte[] EC192_FP_G_Y = new byte[]{
+ (byte) 0x07, (byte) 0x19, (byte) 0x2B, (byte) 0x95,
+ (byte) 0xFF, (byte) 0xC8, (byte) 0xDA, (byte) 0x78,
+ (byte) 0x63, (byte) 0x10, (byte) 0x11, (byte) 0xED,
+ (byte) 0x6B, (byte) 0x24, (byte) 0xCD, (byte) 0xD5,
+ (byte) 0x73, (byte) 0xF9, (byte) 0x77, (byte) 0xA1,
+ (byte) 0x1E, (byte) 0x79, (byte) 0x48, (byte) 0x11
+ };
+ // Order of G
+ public static final byte[] EC192_FP_R = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x99, (byte) 0xDE, (byte) 0xF8, (byte) 0x36,
+ (byte) 0x14, (byte) 0x6B, (byte) 0xC9, (byte) 0xB1,
+ (byte) 0xB4, (byte) 0xD2, (byte) 0x28, (byte) 0x31
+ };
+ // cofactor of G
+ public static final short EC192_FP_K = 1;
+
+ // secp224r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC224_FP_P = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
+ };
+
+ public static final byte[] EC224_FP_A = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE
+ };
+
+ public static final byte[] EC224_FP_B = new byte[]{
+ (byte) 0xB4, (byte) 0x05, (byte) 0x0A, (byte) 0x85,
+ (byte) 0x0C, (byte) 0x04, (byte) 0xB3, (byte) 0xAB,
+ (byte) 0xF5, (byte) 0x41, (byte) 0x32, (byte) 0x56,
+ (byte) 0x50, (byte) 0x44, (byte) 0xB0, (byte) 0xB7,
+ (byte) 0xD7, (byte) 0xBF, (byte) 0xD8, (byte) 0xBA,
+ (byte) 0x27, (byte) 0x0B, (byte) 0x39, (byte) 0x43,
+ (byte) 0x23, (byte) 0x55, (byte) 0xFF, (byte) 0xB4
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC224_FP_G_X = new byte[]{
+ (byte) 0xB7, (byte) 0x0E, (byte) 0x0C, (byte) 0xBD,
+ (byte) 0x6B, (byte) 0xB4, (byte) 0xBF, (byte) 0x7F,
+ (byte) 0x32, (byte) 0x13, (byte) 0x90, (byte) 0xB9,
+ (byte) 0x4A, (byte) 0x03, (byte) 0xC1, (byte) 0xD3,
+ (byte) 0x56, (byte) 0xC2, (byte) 0x11, (byte) 0x22,
+ (byte) 0x34, (byte) 0x32, (byte) 0x80, (byte) 0xD6,
+ (byte) 0x11, (byte) 0x5C, (byte) 0x1D, (byte) 0x21
+ };
+ // second part of G uncompressed
+ public static final byte[] EC224_FP_G_Y = new byte[]{
+ (byte) 0xBD, (byte) 0x37, (byte) 0x63, (byte) 0x88,
+ (byte) 0xB5, (byte) 0xF7, (byte) 0x23, (byte) 0xFB,
+ (byte) 0x4C, (byte) 0x22, (byte) 0xDF, (byte) 0xE6,
+ (byte) 0xCD, (byte) 0x43, (byte) 0x75, (byte) 0xA0,
+ (byte) 0x5A, (byte) 0x07, (byte) 0x47, (byte) 0x64,
+ (byte) 0x44, (byte) 0xD5, (byte) 0x81, (byte) 0x99,
+ (byte) 0x85, (byte) 0x00, (byte) 0x7E, (byte) 0x34
+ };
+ // Order of G
+ public static final byte[] EC224_FP_R = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0x16, (byte) 0xA2,
+ (byte) 0xE0, (byte) 0xB8, (byte) 0xF0, (byte) 0x3E,
+ (byte) 0x13, (byte) 0xDD, (byte) 0x29, (byte) 0x45,
+ (byte) 0x5C, (byte) 0x5C, (byte) 0x2A, (byte) 0x3D
+ };
+ // cofactor of G
+ public static final short EC224_FP_K = 1;
+
+ // secp256r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC256_FP_P = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+ };
+ public static final byte[] EC256_FP_A = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC
+ };
+ public static final byte[] EC256_FP_B = new byte[]{
+ (byte) 0x5A, (byte) 0xC6, (byte) 0x35, (byte) 0xD8,
+ (byte) 0xAA, (byte) 0x3A, (byte) 0x93, (byte) 0xE7,
+ (byte) 0xB3, (byte) 0xEB, (byte) 0xBD, (byte) 0x55,
+ (byte) 0x76, (byte) 0x98, (byte) 0x86, (byte) 0xBC,
+ (byte) 0x65, (byte) 0x1D, (byte) 0x06, (byte) 0xB0,
+ (byte) 0xCC, (byte) 0x53, (byte) 0xB0, (byte) 0xF6,
+ (byte) 0x3B, (byte) 0xCE, (byte) 0x3C, (byte) 0x3E,
+ (byte) 0x27, (byte) 0xD2, (byte) 0x60, (byte) 0x4B
+ };
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC256_FP_G_X = new byte[]{
+ (byte) 0x6B, (byte) 0x17, (byte) 0xD1, (byte) 0xF2,
+ (byte) 0xE1, (byte) 0x2C, (byte) 0x42, (byte) 0x47,
+ (byte) 0xF8, (byte) 0xBC, (byte) 0xE6, (byte) 0xE5,
+ (byte) 0x63, (byte) 0xA4, (byte) 0x40, (byte) 0xF2,
+ (byte) 0x77, (byte) 0x03, (byte) 0x7D, (byte) 0x81,
+ (byte) 0x2D, (byte) 0xEB, (byte) 0x33, (byte) 0xA0,
+ (byte) 0xF4, (byte) 0xA1, (byte) 0x39, (byte) 0x45,
+ (byte) 0xD8, (byte) 0x98, (byte) 0xC2, (byte) 0x96
+ };
+ // second part of G uncompressed
+ public static final byte[] EC256_FP_G_Y = new byte[]{
+ (byte) 0x4F, (byte) 0xE3, (byte) 0x42, (byte) 0xE2,
+ (byte) 0xFE, (byte) 0x1A, (byte) 0x7F, (byte) 0x9B,
+ (byte) 0x8E, (byte) 0xE7, (byte) 0xEB, (byte) 0x4A,
+ (byte) 0x7C, (byte) 0x0F, (byte) 0x9E, (byte) 0x16,
+ (byte) 0x2B, (byte) 0xCE, (byte) 0x33, (byte) 0x57,
+ (byte) 0x6B, (byte) 0x31, (byte) 0x5E, (byte) 0xCE,
+ (byte) 0xCB, (byte) 0xB6, (byte) 0x40, (byte) 0x68,
+ (byte) 0x37, (byte) 0xBF, (byte) 0x51, (byte) 0xF5
+ };
+ // Order of G
+ public static final byte[] EC256_FP_R = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xBC, (byte) 0xE6, (byte) 0xFA, (byte) 0xAD,
+ (byte) 0xA7, (byte) 0x17, (byte) 0x9E, (byte) 0x84,
+ (byte) 0xF3, (byte) 0xB9, (byte) 0xCA, (byte) 0xC2,
+ (byte) 0xFC, (byte) 0x63, (byte) 0x25, (byte) 0x51
+ };
+ // cofactor of G
+ public static final short EC256_FP_K = 1;
+
+ // secp384r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC384_FP_P = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+ };
+
+ public static final byte[] EC384_FP_A = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC
+ };
+
+ public static final byte[] EC384_FP_B = new byte[]{
+ (byte) 0xB3, (byte) 0x31, (byte) 0x2F, (byte) 0xA7,
+ (byte) 0xE2, (byte) 0x3E, (byte) 0xE7, (byte) 0xE4,
+ (byte) 0x98, (byte) 0x8E, (byte) 0x05, (byte) 0x6B,
+ (byte) 0xE3, (byte) 0xF8, (byte) 0x2D, (byte) 0x19,
+ (byte) 0x18, (byte) 0x1D, (byte) 0x9C, (byte) 0x6E,
+ (byte) 0xFE, (byte) 0x81, (byte) 0x41, (byte) 0x12,
+ (byte) 0x03, (byte) 0x14, (byte) 0x08, (byte) 0x8F,
+ (byte) 0x50, (byte) 0x13, (byte) 0x87, (byte) 0x5A,
+ (byte) 0xC6, (byte) 0x56, (byte) 0x39, (byte) 0x8D,
+ (byte) 0x8A, (byte) 0x2E, (byte) 0xD1, (byte) 0x9D,
+ (byte) 0x2A, (byte) 0x85, (byte) 0xC8, (byte) 0xED,
+ (byte) 0xD3, (byte) 0xEC, (byte) 0x2A, (byte) 0xEF
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC384_FP_G_X = new byte[]{
+ (byte) 0xAA, (byte) 0x87, (byte) 0xCA, (byte) 0x22,
+ (byte) 0xBE, (byte) 0x8B, (byte) 0x05, (byte) 0x37,
+ (byte) 0x8E, (byte) 0xB1, (byte) 0xC7, (byte) 0x1E,
+ (byte) 0xF3, (byte) 0x20, (byte) 0xAD, (byte) 0x74,
+ (byte) 0x6E, (byte) 0x1D, (byte) 0x3B, (byte) 0x62,
+ (byte) 0x8B, (byte) 0xA7, (byte) 0x9B, (byte) 0x98,
+ (byte) 0x59, (byte) 0xF7, (byte) 0x41, (byte) 0xE0,
+ (byte) 0x82, (byte) 0x54, (byte) 0x2A, (byte) 0x38,
+ (byte) 0x55, (byte) 0x02, (byte) 0xF2, (byte) 0x5D,
+ (byte) 0xBF, (byte) 0x55, (byte) 0x29, (byte) 0x6C,
+ (byte) 0x3A, (byte) 0x54, (byte) 0x5E, (byte) 0x38,
+ (byte) 0x72, (byte) 0x76, (byte) 0x0A, (byte) 0xB7
+ };
+ // second part of G uncompressed
+ public static final byte[] EC384_FP_G_Y = new byte[]{
+ (byte) 0x36, (byte) 0x17, (byte) 0xDE, (byte) 0x4A,
+ (byte) 0x96, (byte) 0x26, (byte) 0x2C, (byte) 0x6F,
+ (byte) 0x5D, (byte) 0x9E, (byte) 0x98, (byte) 0xBF,
+ (byte) 0x92, (byte) 0x92, (byte) 0xDC, (byte) 0x29,
+ (byte) 0xF8, (byte) 0xF4, (byte) 0x1D, (byte) 0xBD,
+ (byte) 0x28, (byte) 0x9A, (byte) 0x14, (byte) 0x7C,
+ (byte) 0xE9, (byte) 0xDA, (byte) 0x31, (byte) 0x13,
+ (byte) 0xB5, (byte) 0xF0, (byte) 0xB8, (byte) 0xC0,
+ (byte) 0x0A, (byte) 0x60, (byte) 0xB1, (byte) 0xCE,
+ (byte) 0x1D, (byte) 0x7E, (byte) 0x81, (byte) 0x9D,
+ (byte) 0x7A, (byte) 0x43, (byte) 0x1D, (byte) 0x7C,
+ (byte) 0x90, (byte) 0xEA, (byte) 0x0E, (byte) 0x5F
+ };
+
+ // Order of G
+ public static final byte[] EC384_FP_R = new byte[]{
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xC7, (byte) 0x63, (byte) 0x4D, (byte) 0x81,
+ (byte) 0xF4, (byte) 0x37, (byte) 0x2D, (byte) 0xDF,
+ (byte) 0x58, (byte) 0x1A, (byte) 0x0D, (byte) 0xB2,
+ (byte) 0x48, (byte) 0xB0, (byte) 0xA7, (byte) 0x7A,
+ (byte) 0xEC, (byte) 0xEC, (byte) 0x19, (byte) 0x6A,
+ (byte) 0xCC, (byte) 0xC5, (byte) 0x29, (byte) 0x73
+ };
+ // cofactor of G
+ public static final short EC384_FP_K = 1;
+
+
+ // secp521r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC521_FP_P = new byte[]{
+ (byte) 0x01, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+ };
+
+ public static final byte[] EC521_FP_A = new byte[]{
+ (byte) 0x01, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC
+ };
+
+ public static final byte[] EC521_FP_B = new byte[]{
+ (byte) 0x00, (byte) 0x51, (byte) 0x95, (byte) 0x3E,
+ (byte) 0xB9, (byte) 0x61, (byte) 0x8E, (byte) 0x1C,
+ (byte) 0x9A, (byte) 0x1F, (byte) 0x92, (byte) 0x9A,
+ (byte) 0x21, (byte) 0xA0, (byte) 0xB6, (byte) 0x85,
+ (byte) 0x40, (byte) 0xEE, (byte) 0xA2, (byte) 0xDA,
+ (byte) 0x72, (byte) 0x5B, (byte) 0x99, (byte) 0xB3,
+ (byte) 0x15, (byte) 0xF3, (byte) 0xB8, (byte) 0xB4,
+ (byte) 0x89, (byte) 0x91, (byte) 0x8E, (byte) 0xF1,
+ (byte) 0x09, (byte) 0xE1, (byte) 0x56, (byte) 0x19,
+ (byte) 0x39, (byte) 0x51, (byte) 0xEC, (byte) 0x7E,
+ (byte) 0x93, (byte) 0x7B, (byte) 0x16, (byte) 0x52,
+ (byte) 0xC0, (byte) 0xBD, (byte) 0x3B, (byte) 0xB1,
+ (byte) 0xBF, (byte) 0x07, (byte) 0x35, (byte) 0x73,
+ (byte) 0xDF, (byte) 0x88, (byte) 0x3D, (byte) 0x2C,
+ (byte) 0x34, (byte) 0xF1, (byte) 0xEF, (byte) 0x45,
+ (byte) 0x1F, (byte) 0xD4, (byte) 0x6B, (byte) 0x50,
+ (byte) 0x3F, (byte) 0x00
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC521_FP_G_X = new byte[]{
+ (byte) 0x00, (byte) 0xC6, (byte) 0x85, (byte) 0x8E,
+ (byte) 0x06, (byte) 0xB7, (byte) 0x04, (byte) 0x04,
+ (byte) 0xE9, (byte) 0xCD, (byte) 0x9E, (byte) 0x3E,
+ (byte) 0xCB, (byte) 0x66, (byte) 0x23, (byte) 0x95,
+ (byte) 0xB4, (byte) 0x42, (byte) 0x9C, (byte) 0x64,
+ (byte) 0x81, (byte) 0x39, (byte) 0x05, (byte) 0x3F,
+ (byte) 0xB5, (byte) 0x21, (byte) 0xF8, (byte) 0x28,
+ (byte) 0xAF, (byte) 0x60, (byte) 0x6B, (byte) 0x4D,
+ (byte) 0x3D, (byte) 0xBA, (byte) 0xA1, (byte) 0x4B,
+ (byte) 0x5E, (byte) 0x77, (byte) 0xEF, (byte) 0xE7,
+ (byte) 0x59, (byte) 0x28, (byte) 0xFE, (byte) 0x1D,
+ (byte) 0xC1, (byte) 0x27, (byte) 0xA2, (byte) 0xFF,
+ (byte) 0xA8, (byte) 0xDE, (byte) 0x33, (byte) 0x48,
+ (byte) 0xB3, (byte) 0xC1, (byte) 0x85, (byte) 0x6A,
+ (byte) 0x42, (byte) 0x9B, (byte) 0xF9, (byte) 0x7E,
+ (byte) 0x7E, (byte) 0x31, (byte) 0xC2, (byte) 0xE5,
+ (byte) 0xBD, (byte) 0x66
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC521_FP_G_Y = new byte[]{
+ (byte) 0x01, (byte) 0x18, (byte) 0x39, (byte) 0x29,
+ (byte) 0x6A, (byte) 0x78, (byte) 0x9A, (byte) 0x3B,
+ (byte) 0xC0, (byte) 0x04, (byte) 0x5C, (byte) 0x8A,
+ (byte) 0x5F, (byte) 0xB4, (byte) 0x2C, (byte) 0x7D,
+ (byte) 0x1B, (byte) 0xD9, (byte) 0x98, (byte) 0xF5,
+ (byte) 0x44, (byte) 0x49, (byte) 0x57, (byte) 0x9B,
+ (byte) 0x44, (byte) 0x68, (byte) 0x17, (byte) 0xAF,
+ (byte) 0xBD, (byte) 0x17, (byte) 0x27, (byte) 0x3E,
+ (byte) 0x66, (byte) 0x2C, (byte) 0x97, (byte) 0xEE,
+ (byte) 0x72, (byte) 0x99, (byte) 0x5E, (byte) 0xF4,
+ (byte) 0x26, (byte) 0x40, (byte) 0xC5, (byte) 0x50,
+ (byte) 0xB9, (byte) 0x01, (byte) 0x3F, (byte) 0xAD,
+ (byte) 0x07, (byte) 0x61, (byte) 0x35, (byte) 0x3C,
+ (byte) 0x70, (byte) 0x86, (byte) 0xA2, (byte) 0x72,
+ (byte) 0xC2, (byte) 0x40, (byte) 0x88, (byte) 0xBE,
+ (byte) 0x94, (byte) 0x76, (byte) 0x9F, (byte) 0xD1,
+ (byte) 0x66, (byte) 0x50
+ };
+
+ // Order of G
+ public static final byte[] EC521_FP_R = new byte[]{
+ (byte) 0x01, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFA,
+ (byte) 0x51, (byte) 0x86, (byte) 0x87, (byte) 0x83,
+ (byte) 0xBF, (byte) 0x2F, (byte) 0x96, (byte) 0x6B,
+ (byte) 0x7F, (byte) 0xCC, (byte) 0x01, (byte) 0x48,
+ (byte) 0xF7, (byte) 0x09, (byte) 0xA5, (byte) 0xD0,
+ (byte) 0x3B, (byte) 0xB5, (byte) 0xC9, (byte) 0xB8,
+ (byte) 0x89, (byte) 0x9C, (byte) 0x47, (byte) 0xAE,
+ (byte) 0xBB, (byte) 0x6F, (byte) 0xB7, (byte) 0x1E,
+ (byte) 0x91, (byte) 0x38, (byte) 0x64, (byte) 0x09
+ };
+
+ // cofactor of G
+ public static final short EC521_FP_K = 1;
+
+ //sect163r1 from http://www.secg.org/sec2-v2.pdf
+ // [short i1, short i2, short i3] f = x^163 + x^i1 + x^i2 + x^i3 + 1
+ public static final byte[] EC163_F2M_F = new byte[]{
+ (byte) 0x00, (byte) 0x07,
+ (byte) 0x00, (byte) 0x06,
+ (byte) 0x00, (byte) 0x03
+ };
+
+ public static final byte[] EC163_F2M_A = new byte[]{
+ (byte) 0x07, (byte) 0xB6, (byte) 0x88, (byte) 0x2C,
+ (byte) 0xAA, (byte) 0xEF, (byte) 0xA8, (byte) 0x4F,
+ (byte) 0x95, (byte) 0x54, (byte) 0xFF, (byte) 0x84,
+ (byte) 0x28, (byte) 0xBD, (byte) 0x88, (byte) 0xE2,
+ (byte) 0x46, (byte) 0xD2, (byte) 0x78, (byte) 0x2A,
+ (byte) 0xE2
+ };
+
+ public static final byte[] EC163_F2M_B = new byte[]{
+ (byte) 0x07, (byte) 0x13, (byte) 0x61, (byte) 0x2D,
+ (byte) 0xCD, (byte) 0xDC, (byte) 0xB4, (byte) 0x0A,
+ (byte) 0xAB, (byte) 0x94, (byte) 0x6B, (byte) 0xDA,
+ (byte) 0x29, (byte) 0xCA, (byte) 0x91, (byte) 0xF7,
+ (byte) 0x3A, (byte) 0xF9, (byte) 0x58, (byte) 0xAF,
+ (byte) 0xD9
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC163_F2M_G_X = new byte[]{
+ (byte) 0x03, (byte) 0x69, (byte) 0x97, (byte) 0x96,
+ (byte) 0x97, (byte) 0xAB, (byte) 0x43, (byte) 0x89,
+ (byte) 0x77, (byte) 0x89, (byte) 0x56, (byte) 0x67,
+ (byte) 0x89, (byte) 0x56, (byte) 0x7F, (byte) 0x78,
+ (byte) 0x7A, (byte) 0x78, (byte) 0x76, (byte) 0xA6,
+ (byte) 0x54
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC163_F2M_G_Y = new byte[]{
+ (byte) 0x00, (byte) 0x43, (byte) 0x5E, (byte) 0xDB,
+ (byte) 0x42, (byte) 0xEF, (byte) 0xAF, (byte) 0xB2,
+ (byte) 0x98, (byte) 0x9D, (byte) 0x51, (byte) 0xFE,
+ (byte) 0xFC, (byte) 0xE3, (byte) 0xC8, (byte) 0x09,
+ (byte) 0x88, (byte) 0xF4, (byte) 0x1F, (byte) 0xF8,
+ (byte) 0x83
+ };
+
+ // order of G
+ public static final byte[] EC163_F2M_R = new byte[]{
+ (byte) 0x03, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x48,
+ (byte) 0xAA, (byte) 0xB6, (byte) 0x89, (byte) 0xC2,
+ (byte) 0x9C, (byte) 0xA7, (byte) 0x10, (byte) 0x27,
+ (byte) 0x9B
+ };
+
+ // cofactor of G
+ public static final short EC163_F2M_K = 2;
+
+ //sect233r1 from http://www.secg.org/sec2-v2.pdf
+ // [short i1, short i2, short i3] f = x^233 + x^i1 + 1
+ public static final byte[] EC233_F2M_F = new byte[]{
+ (byte) 0x00, (byte) 0x4a
+ };
+
+ public static final byte[] EC233_F2M_A = new byte[]{
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01
+ };
+
+ public static final byte[] EC233_F2M_B = new byte[]{
+ (byte) 0x00, (byte) 0x66, (byte) 0x64, (byte) 0x7E,
+ (byte) 0xDE, (byte) 0x6C, (byte) 0x33, (byte) 0x2C,
+ (byte) 0x7F, (byte) 0x8C, (byte) 0x09, (byte) 0x23,
+ (byte) 0xBB, (byte) 0x58, (byte) 0x21, (byte) 0x3B,
+ (byte) 0x33, (byte) 0x3B, (byte) 0x20, (byte) 0xE9,
+ (byte) 0xCE, (byte) 0x42, (byte) 0x81, (byte) 0xFE,
+ (byte) 0x11, (byte) 0x5F, (byte) 0x7D, (byte) 0x8F,
+ (byte) 0x90, (byte) 0xAD
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC233_F2M_G_X = new byte[]{
+ (byte) 0x00, (byte) 0xFA, (byte) 0xC9, (byte) 0xDF,
+ (byte) 0xCB, (byte) 0xAC, (byte) 0x83, (byte) 0x13,
+ (byte) 0xBB, (byte) 0x21, (byte) 0x39, (byte) 0xF1,
+ (byte) 0xBB, (byte) 0x75, (byte) 0x5F, (byte) 0xEF,
+ (byte) 0x65, (byte) 0xBC, (byte) 0x39, (byte) 0x1F,
+ (byte) 0x8B, (byte) 0x36, (byte) 0xF8, (byte) 0xF8,
+ (byte) 0xEB, (byte) 0x73, (byte) 0x71, (byte) 0xFD,
+ (byte) 0x55, (byte) 0x8B
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC233_F2M_G_Y = new byte[]{
+ (byte) 0x01, (byte) 0x00, (byte) 0x6A, (byte) 0x08,
+ (byte) 0xA4, (byte) 0x19, (byte) 0x03, (byte) 0x35,
+ (byte) 0x06, (byte) 0x78, (byte) 0xE5, (byte) 0x85,
+ (byte) 0x28, (byte) 0xBE, (byte) 0xBF, (byte) 0x8A,
+ (byte) 0x0B, (byte) 0xEF, (byte) 0xF8, (byte) 0x67,
+ (byte) 0xA7, (byte) 0xCA, (byte) 0x36, (byte) 0x71,
+ (byte) 0x6F, (byte) 0x7E, (byte) 0x01, (byte) 0xF8,
+ (byte) 0x10, (byte) 0x52
+ };
+
+ // order of G
+ public static final byte[] EC233_F2M_R = new byte[]{
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x13,
+ (byte) 0xE9, (byte) 0x74, (byte) 0xE7, (byte) 0x2F,
+ (byte) 0x8A, (byte) 0x69, (byte) 0x22, (byte) 0x03,
+ (byte) 0x1D, (byte) 0x26, (byte) 0x03, (byte) 0xCF,
+ (byte) 0xE0, (byte) 0xD7
+ };
+
+ // cofactor of G
+ public static final short EC233_F2M_K = 2;
+
+ //sect283r1 from http://www.secg.org/sec2-v2.pdf
+ // [short i1, short i2, short i3] f = x^283 + x^i1 + x^i2 + x^i3 + 1
+ public static final byte[] EC283_F2M_F = new byte[]{
+ (byte) 0x00, (byte) 0x0c,
+ (byte) 0x00, (byte) 0x07,
+ (byte) 0x00, (byte) 0x05
+ };
+
+ public static final byte[] EC283_F2M_A = new byte[]{
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
+ };
+
+ public static final byte[] EC283_F2M_B = new byte[]{
+ (byte) 0x02, (byte) 0x7B, (byte) 0x68, (byte) 0x0A,
+ (byte) 0xC8, (byte) 0xB8, (byte) 0x59, (byte) 0x6D,
+ (byte) 0xA5, (byte) 0xA4, (byte) 0xAF, (byte) 0x8A,
+ (byte) 0x19, (byte) 0xA0, (byte) 0x30, (byte) 0x3F,
+ (byte) 0xCA, (byte) 0x97, (byte) 0xFD, (byte) 0x76,
+ (byte) 0x45, (byte) 0x30, (byte) 0x9F, (byte) 0xA2,
+ (byte) 0xA5, (byte) 0x81, (byte) 0x48, (byte) 0x5A,
+ (byte) 0xF6, (byte) 0x26, (byte) 0x3E, (byte) 0x31,
+ (byte) 0x3B, (byte) 0x79, (byte) 0xA2, (byte) 0xF5
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC283_F2M_G_X = new byte[]{
+ (byte) 0x05, (byte) 0xF9, (byte) 0x39, (byte) 0x25,
+ (byte) 0x8D, (byte) 0xB7, (byte) 0xDD, (byte) 0x90,
+ (byte) 0xE1, (byte) 0x93, (byte) 0x4F, (byte) 0x8C,
+ (byte) 0x70, (byte) 0xB0, (byte) 0xDF, (byte) 0xEC,
+ (byte) 0x2E, (byte) 0xED, (byte) 0x25, (byte) 0xB8,
+ (byte) 0x55, (byte) 0x7E, (byte) 0xAC, (byte) 0x9C,
+ (byte) 0x80, (byte) 0xE2, (byte) 0xE1, (byte) 0x98,
+ (byte) 0xF8, (byte) 0xCD, (byte) 0xBE, (byte) 0xCD,
+ (byte) 0x86, (byte) 0xB1, (byte) 0x20, (byte) 0x53
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC283_F2M_G_Y = new byte[]{
+ (byte) 0x03, (byte) 0x67, (byte) 0x68, (byte) 0x54,
+ (byte) 0xFE, (byte) 0x24, (byte) 0x14, (byte) 0x1C,
+ (byte) 0xB9, (byte) 0x8F, (byte) 0xE6, (byte) 0xD4,
+ (byte) 0xB2, (byte) 0x0D, (byte) 0x02, (byte) 0xB4,
+ (byte) 0x51, (byte) 0x6F, (byte) 0xF7, (byte) 0x02,
+ (byte) 0x35, (byte) 0x0E, (byte) 0xDD, (byte) 0xB0,
+ (byte) 0x82, (byte) 0x67, (byte) 0x79, (byte) 0xC8,
+ (byte) 0x13, (byte) 0xF0, (byte) 0xDF, (byte) 0x45,
+ (byte) 0xBE, (byte) 0x81, (byte) 0x12, (byte) 0xF4
+ };
+
+ // order of G
+ public static final byte[] EC283_F2M_R = new byte[]{
+ (byte) 0x03, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xEF, (byte) 0x90,
+ (byte) 0x39, (byte) 0x96, (byte) 0x60, (byte) 0xFC,
+ (byte) 0x93, (byte) 0x8A, (byte) 0x90, (byte) 0x16,
+ (byte) 0x5B, (byte) 0x04, (byte) 0x2A, (byte) 0x7C,
+ (byte) 0xEF, (byte) 0xAD, (byte) 0xB3, (byte) 0x07
+ };
+
+ // cofactor of G
+ public static final short EC283_F2M_K = 2;
+
+ //sect409r1 from http://www.secg.org/sec2-v2.pdf
+ // [short i1, short i2, short i3] f = x^409 + x^i1 + 1
+ public static final byte[] EC409_F2M_F = new byte[]{
+ (byte) 0x00, (byte) 0x57
+ };
+
+ public static final byte[] EC409_F2M_A = new byte[]{
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
+ };
+
+ public static final byte[] EC409_F2M_B = new byte[]{
+ (byte) 0x00, (byte) 0x21, (byte) 0xA5, (byte) 0xC2,
+ (byte) 0xC8, (byte) 0xEE, (byte) 0x9F, (byte) 0xEB,
+ (byte) 0x5C, (byte) 0x4B, (byte) 0x9A, (byte) 0x75,
+ (byte) 0x3B, (byte) 0x7B, (byte) 0x47, (byte) 0x6B,
+ (byte) 0x7F, (byte) 0xD6, (byte) 0x42, (byte) 0x2E,
+ (byte) 0xF1, (byte) 0xF3, (byte) 0xDD, (byte) 0x67,
+ (byte) 0x47, (byte) 0x61, (byte) 0xFA, (byte) 0x99,
+ (byte) 0xD6, (byte) 0xAC, (byte) 0x27, (byte) 0xC8,
+ (byte) 0xA9, (byte) 0xA1, (byte) 0x97, (byte) 0xB2,
+ (byte) 0x72, (byte) 0x82, (byte) 0x2F, (byte) 0x6C,
+ (byte) 0xD5, (byte) 0x7A, (byte) 0x55, (byte) 0xAA,
+ (byte) 0x4F, (byte) 0x50, (byte) 0xAE, (byte) 0x31,
+ (byte) 0x7B, (byte) 0x13, (byte) 0x54, (byte) 0x5F
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC409_F2M_G_X = new byte[]{
+ (byte) 0x01, (byte) 0x5D, (byte) 0x48, (byte) 0x60,
+ (byte) 0xD0, (byte) 0x88, (byte) 0xDD, (byte) 0xB3,
+ (byte) 0x49, (byte) 0x6B, (byte) 0x0C, (byte) 0x60,
+ (byte) 0x64, (byte) 0x75, (byte) 0x62, (byte) 0x60,
+ (byte) 0x44, (byte) 0x1C, (byte) 0xDE, (byte) 0x4A,
+ (byte) 0xF1, (byte) 0x77, (byte) 0x1D, (byte) 0x4D,
+ (byte) 0xB0, (byte) 0x1F, (byte) 0xFE, (byte) 0x5B,
+ (byte) 0x34, (byte) 0xE5, (byte) 0x97, (byte) 0x03,
+ (byte) 0xDC, (byte) 0x25, (byte) 0x5A, (byte) 0x86,
+ (byte) 0x8A, (byte) 0x11, (byte) 0x80, (byte) 0x51,
+ (byte) 0x56, (byte) 0x03, (byte) 0xAE, (byte) 0xAB,
+ (byte) 0x60, (byte) 0x79, (byte) 0x4E, (byte) 0x54,
+ (byte) 0xBB, (byte) 0x79, (byte) 0x96, (byte) 0xA7
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC409_F2M_G_Y = new byte[]{
+ (byte) 0x00, (byte) 0x61, (byte) 0xB1, (byte) 0xCF,
+ (byte) 0xAB, (byte) 0x6B, (byte) 0xE5, (byte) 0xF3,
+ (byte) 0x2B, (byte) 0xBF, (byte) 0xA7, (byte) 0x83,
+ (byte) 0x24, (byte) 0xED, (byte) 0x10, (byte) 0x6A,
+ (byte) 0x76, (byte) 0x36, (byte) 0xB9, (byte) 0xC5,
+ (byte) 0xA7, (byte) 0xBD, (byte) 0x19, (byte) 0x8D,
+ (byte) 0x01, (byte) 0x58, (byte) 0xAA, (byte) 0x4F,
+ (byte) 0x54, (byte) 0x88, (byte) 0xD0, (byte) 0x8F,
+ (byte) 0x38, (byte) 0x51, (byte) 0x4F, (byte) 0x1F,
+ (byte) 0xDF, (byte) 0x4B, (byte) 0x4F, (byte) 0x40,
+ (byte) 0xD2, (byte) 0x18, (byte) 0x1B, (byte) 0x36,
+ (byte) 0x81, (byte) 0xC3, (byte) 0x64, (byte) 0xBA,
+ (byte) 0x02, (byte) 0x73, (byte) 0xC7, (byte) 0x06
+ };
+
+ // order of G
+ public static final byte[] EC409_F2M_R = new byte[]{
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0xE2,
+ (byte) 0xAA, (byte) 0xD6, (byte) 0xA6, (byte) 0x12,
+ (byte) 0xF3, (byte) 0x33, (byte) 0x07, (byte) 0xBE,
+ (byte) 0x5F, (byte) 0xA4, (byte) 0x7C, (byte) 0x3C,
+ (byte) 0x9E, (byte) 0x05, (byte) 0x2F, (byte) 0x83,
+ (byte) 0x81, (byte) 0x64, (byte) 0xCD, (byte) 0x37,
+ (byte) 0xD9, (byte) 0xA2, (byte) 0x11, (byte) 0x73
+ };
+
+ // cofactor of G
+ public static final short EC409_F2M_K = 2;
+
+ //sect571r1 from http://www.secg.org/sec2-v2.pdf
+ // [short i1, short i2, short i3] f = x^571 + x^i1 + x^i2 + x^i3 + 1
+ public static final byte[] EC571_F2M_F = new byte[]{
+ (byte) 0x00, (byte) 0x0a,
+ (byte) 0x00, (byte) 0x05,
+ (byte) 0x00, (byte) 0x02,
+ };
+
+ public static final byte[] EC571_F2M_A = new byte[]{
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01
+ };
+
+ public static final byte[] EC571_F2M_B = new byte[]{
+ (byte) 0x02, (byte) 0xF4, (byte) 0x0E, (byte) 0x7E,
+ (byte) 0x22, (byte) 0x21, (byte) 0xF2, (byte) 0x95,
+ (byte) 0xDE, (byte) 0x29, (byte) 0x71, (byte) 0x17,
+ (byte) 0xB7, (byte) 0xF3, (byte) 0xD6, (byte) 0x2F,
+ (byte) 0x5C, (byte) 0x6A, (byte) 0x97, (byte) 0xFF,
+ (byte) 0xCB, (byte) 0x8C, (byte) 0xEF, (byte) 0xF1,
+ (byte) 0xCD, (byte) 0x6B, (byte) 0xA8, (byte) 0xCE,
+ (byte) 0x4A, (byte) 0x9A, (byte) 0x18, (byte) 0xAD,
+ (byte) 0x84, (byte) 0xFF, (byte) 0xAB, (byte) 0xBD,
+ (byte) 0x8E, (byte) 0xFA, (byte) 0x59, (byte) 0x33,
+ (byte) 0x2B, (byte) 0xE7, (byte) 0xAD, (byte) 0x67,
+ (byte) 0x56, (byte) 0xA6, (byte) 0x6E, (byte) 0x29,
+ (byte) 0x4A, (byte) 0xFD, (byte) 0x18, (byte) 0x5A,
+ (byte) 0x78, (byte) 0xFF, (byte) 0x12, (byte) 0xAA,
+ (byte) 0x52, (byte) 0x0E, (byte) 0x4D, (byte) 0xE7,
+ (byte) 0x39, (byte) 0xBA, (byte) 0xCA, (byte) 0x0C,
+ (byte) 0x7F, (byte) 0xFE, (byte) 0xFF, (byte) 0x7F,
+ (byte) 0x29, (byte) 0x55, (byte) 0x72, (byte) 0x7A
+ };
+
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC571_F2M_G_X = new byte[]{
+ (byte) 0x03, (byte) 0x03, (byte) 0x00, (byte) 0x1D,
+ (byte) 0x34, (byte) 0xB8, (byte) 0x56, (byte) 0x29,
+ (byte) 0x6C, (byte) 0x16, (byte) 0xC0, (byte) 0xD4,
+ (byte) 0x0D, (byte) 0x3C, (byte) 0xD7, (byte) 0x75,
+ (byte) 0x0A, (byte) 0x93, (byte) 0xD1, (byte) 0xD2,
+ (byte) 0x95, (byte) 0x5F, (byte) 0xA8, (byte) 0x0A,
+ (byte) 0xA5, (byte) 0xF4, (byte) 0x0F, (byte) 0xC8,
+ (byte) 0xDB, (byte) 0x7B, (byte) 0x2A, (byte) 0xBD,
+ (byte) 0xBD, (byte) 0xE5, (byte) 0x39, (byte) 0x50,
+ (byte) 0xF4, (byte) 0xC0, (byte) 0xD2, (byte) 0x93,
+ (byte) 0xCD, (byte) 0xD7, (byte) 0x11, (byte) 0xA3,
+ (byte) 0x5B, (byte) 0x67, (byte) 0xFB, (byte) 0x14,
+ (byte) 0x99, (byte) 0xAE, (byte) 0x60, (byte) 0x03,
+ (byte) 0x86, (byte) 0x14, (byte) 0xF1, (byte) 0x39,
+ (byte) 0x4A, (byte) 0xBF, (byte) 0xA3, (byte) 0xB4,
+ (byte) 0xC8, (byte) 0x50, (byte) 0xD9, (byte) 0x27,
+ (byte) 0xE1, (byte) 0xE7, (byte) 0x76, (byte) 0x9C,
+ (byte) 0x8E, (byte) 0xEC, (byte) 0x2D, (byte) 0x19
+ };
+
+ // second part of G uncompressed
+ public static final byte[] EC571_F2M_G_Y = new byte[]{
+ (byte) 0x03, (byte) 0x7B, (byte) 0xF2, (byte) 0x73,
+ (byte) 0x42, (byte) 0xDA, (byte) 0x63, (byte) 0x9B,
+ (byte) 0x6D, (byte) 0xCC, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xB7, (byte) 0x3D, (byte) 0x69, (byte) 0xD7,
+ (byte) 0x8C, (byte) 0x6C, (byte) 0x27, (byte) 0xA6,
+ (byte) 0x00, (byte) 0x9C, (byte) 0xBB, (byte) 0xCA,
+ (byte) 0x19, (byte) 0x80, (byte) 0xF8, (byte) 0x53,
+ (byte) 0x39, (byte) 0x21, (byte) 0xE8, (byte) 0xA6,
+ (byte) 0x84, (byte) 0x42, (byte) 0x3E, (byte) 0x43,
+ (byte) 0xBA, (byte) 0xB0, (byte) 0x8A, (byte) 0x57,
+ (byte) 0x62, (byte) 0x91, (byte) 0xAF, (byte) 0x8F,
+ (byte) 0x46, (byte) 0x1B, (byte) 0xB2, (byte) 0xA8,
+ (byte) 0xB3, (byte) 0x53, (byte) 0x1D, (byte) 0x2F,
+ (byte) 0x04, (byte) 0x85, (byte) 0xC1, (byte) 0x9B,
+ (byte) 0x16, (byte) 0xE2, (byte) 0xF1, (byte) 0x51,
+ (byte) 0x6E, (byte) 0x23, (byte) 0xDD, (byte) 0x3C,
+ (byte) 0x1A, (byte) 0x48, (byte) 0x27, (byte) 0xAF,
+ (byte) 0x1B, (byte) 0x8A, (byte) 0xC1, (byte) 0x5B
+ };
+
+ // order of G
+ public static final byte[] EC571_F2M_R = new byte[]{
+ (byte) 0x03, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xE6, (byte) 0x61, (byte) 0xCE, (byte) 0x18,
+ (byte) 0xFF, (byte) 0x55, (byte) 0x98, (byte) 0x73,
+ (byte) 0x08, (byte) 0x05, (byte) 0x9B, (byte) 0x18,
+ (byte) 0x68, (byte) 0x23, (byte) 0x85, (byte) 0x1E,
+ (byte) 0xC7, (byte) 0xDD, (byte) 0x9C, (byte) 0xA1,
+ (byte) 0x16, (byte) 0x1D, (byte) 0xE9, (byte) 0x3D,
+ (byte) 0x51, (byte) 0x74, (byte) 0xD6, (byte) 0x6E,
+ (byte) 0x83, (byte) 0x82, (byte) 0xE9, (byte) 0xBB,
+ (byte) 0x2F, (byte) 0xE8, (byte) 0x4E, (byte) 0x47
+ };
+
+ // cofactor of G
+ public static final short EC571_F2M_K = 2;
+
+
+ // transformParameter TRANSFORMATION types
+ public static final short TRANSFORMATION_NONE = (short) 0x00;
+ public static final short TRANSFORMATION_FIXED = (short) 0x01;
+ public static final short TRANSFORMATION_FULLRANDOM = (short) 0x02;
+ public static final short TRANSFORMATION_ONEBYTERANDOM = (short) 0x04;
+ public static final short TRANSFORMATION_ZERO = (short) 0x08;
+ public static final short TRANSFORMATION_ONE = (short) 0x10;
+ public static final short TRANSFORMATION_MAX = (short) 0x20;
+ public static final short TRANSFORMATION_INCREMENT = (short) 0x40;
+ public static final short TRANSFORMATION_INFINITY = (short) 0x80;
+ public static final short TRANSFORMATION_COMPRESS = (short) 0x0100;
+ public static final short TRANSFORMATION_COMPRESS_HYBRID = (short) 0x0200;
+ public static final short TRANSFORMATION_04_MASK = (short) 0x0400;
+
+ // toX962 FORM types
+ public static final byte X962_UNCOMPRESSED = (byte) 0x00;
+ public static final byte X962_COMPRESSED = (byte) 0x01;
+ public static final byte X962_HYBRID = (byte) 0x02;
+
+ // Supported embedded curves, getCurveParameter
+ public static final byte CURVE_default = (byte) 0;
+ public static final byte CURVE_external = (byte) 0xff;
+
+ // SECG recommended curves over FP
+ public static final byte CURVE_secp112r1 = (byte) 1;
+ public static final byte CURVE_secp128r1 = (byte) 2;
+ public static final byte CURVE_secp160r1 = (byte) 3;
+ public static final byte CURVE_secp192r1 = (byte) 4;
+ public static final byte CURVE_secp224r1 = (byte) 5;
+ public static final byte CURVE_secp256r1 = (byte) 6;
+ public static final byte CURVE_secp384r1 = (byte) 7;
+ public static final byte CURVE_secp521r1 = (byte) 8;
+
+ public static final byte FP_CURVES = (byte) 8;
+
+ // SECG recommended curves over F2M
+ public static final byte CURVE_sect163r1 = (byte) 9;
+ public static final byte CURVE_sect233r1 = (byte) 10;
+ public static final byte CURVE_sect283r1 = (byte) 11;
+ public static final byte CURVE_sect409r1 = (byte) 12;
+ public static final byte CURVE_sect571r1 = (byte) 13;
+
+ public static final byte F2M_CURVES = (byte) 13;
+
+ public static final short[] FP_SIZES = new short[]{112, 128, 160, 192, 224, 256, 384, 521};
+ public static final short[] F2M_SIZES = new short[]{163, 233, 283, 409, 571};
+
+ public static final byte ALG_EC_F2M = 4;
+ public static final byte ALG_EC_FP = 5;
+
+ // Class javacard.security.KeyAgreement
+ // javacard.security.KeyAgreement Fields:
+ public static final byte KeyAgreement_ALG_EC_SVDP_DH = 1;
+ public static final byte KeyAgreement_ALG_EC_SVDP_DH_KDF = 1;
+ public static final byte KeyAgreement_ALG_EC_SVDP_DHC = 2;
+ public static final byte KeyAgreement_ALG_EC_SVDP_DHC_KDF = 2;
+ public static final byte KeyAgreement_ALG_EC_SVDP_DH_PLAIN = 3;
+ public static final byte KeyAgreement_ALG_EC_SVDP_DHC_PLAIN = 4;
+ public static final byte KeyAgreement_ALG_EC_PACE_GM = 5;
+ public static final byte KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY = 6;
+
+ public static final byte[] KA_TYPES = new byte[]{
+ KeyAgreement_ALG_EC_SVDP_DH,
+ //KeyAgreement_ALG_EC_SVDP_DH_KDF, //duplicate
+ KeyAgreement_ALG_EC_SVDP_DHC,
+ //KeyAgreement_ALG_EC_SVDP_DHC_KDF, //duplicate
+ KeyAgreement_ALG_EC_SVDP_DH_PLAIN,
+ KeyAgreement_ALG_EC_SVDP_DHC_PLAIN,
+ KeyAgreement_ALG_EC_PACE_GM,
+ KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY
+ };
+
+ // Class javacard.security.Signature
+ // javacard.security.Signature Fields:
+ public static final byte Signature_ALG_ECDSA_SHA = 17;
+ public static final byte Signature_ALG_ECDSA_SHA_224 = 37;
+ public static final byte Signature_ALG_ECDSA_SHA_256 = 33;
+ public static final byte Signature_ALG_ECDSA_SHA_384 = 34;
+ public static final byte Signature_ALG_ECDSA_SHA_512 = 38;
+
+ public static final byte[] SIG_TYPES = new byte[]{
+ Signature_ALG_ECDSA_SHA,
+ Signature_ALG_ECDSA_SHA_224,
+ Signature_ALG_ECDSA_SHA_256,
+ Signature_ALG_ECDSA_SHA_384,
+ Signature_ALG_ECDSA_SHA_512
+ };
+
+ public static byte getCurve(short keyLength, byte keyClass) {
+ if (keyClass == ALG_EC_FP) {
+ switch (keyLength) {
+ case (short) 112:
+ return CURVE_secp112r1;
+ case (short) 128:
+ return CURVE_secp128r1;
+ case (short) 160:
+ return CURVE_secp160r1;
+ case (short) 192:
+ return CURVE_secp192r1;
+ case (short) 224:
+ return CURVE_secp224r1;
+ case (short) 256:
+ return CURVE_secp256r1;
+ case (short) 384:
+ return CURVE_secp384r1;
+ case (short) 521:
+ return CURVE_secp521r1;
+ default:
+ throw new IllegalArgumentException("Unsupported keyLength and keyClass.");
+ }
+ } else if (keyClass == ALG_EC_F2M) {
+ switch (keyLength) {
+ case (short) 163:
+ return CURVE_sect163r1;
+ case (short) 233:
+ return CURVE_sect233r1;
+ case (short) 283:
+ return CURVE_sect283r1;
+ case (short) 409:
+ return CURVE_sect409r1;
+ case (short) 571:
+ return CURVE_sect571r1;
+ default:
+ throw new IllegalArgumentException("Unsupported keyLength and keyClass.");
+ }
+ } else {
+ throw new IllegalArgumentException("Unsupported keyClass.");
+ }
+ }
+
+ public static byte[] getCurveParameter(byte curve, short param) {
+ byte alg = getCurveType(curve);
+ switch (curve) {
+ case CURVE_secp112r1: {
+ EC_FP_P = EC112_FP_P;
+ EC_A = EC112_FP_A;
+ EC_B = EC112_FP_B;
+ EC_G_X = EC112_FP_G_X;
+ EC_G_Y = EC112_FP_G_Y;
+ EC_R = EC112_FP_R;
+ EC_K = EC112_FP_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_secp128r1: {
+ EC_FP_P = EC128_FP_P;
+ EC_A = EC128_FP_A;
+ EC_B = EC128_FP_B;
+ EC_G_X = EC128_FP_G_X;
+ EC_G_Y = EC128_FP_G_Y;
+ EC_R = EC128_FP_R;
+ EC_K = EC128_FP_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_secp160r1: {
+ EC_FP_P = EC160_FP_P;
+ EC_A = EC160_FP_A;
+ EC_B = EC160_FP_B;
+ EC_G_X = EC160_FP_G_X;
+ EC_G_Y = EC160_FP_G_Y;
+ EC_R = EC160_FP_R;
+ EC_K = EC160_FP_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_secp192r1: {
+ EC_FP_P = EC192_FP_P;
+ EC_A = EC192_FP_A;
+ EC_B = EC192_FP_B;
+ EC_G_X = EC192_FP_G_X;
+ EC_G_Y = EC192_FP_G_Y;
+ EC_R = EC192_FP_R;
+ EC_K = EC192_FP_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_secp224r1: {
+ EC_FP_P = EC224_FP_P;
+ EC_A = EC224_FP_A;
+ EC_B = EC224_FP_B;
+ EC_G_X = EC224_FP_G_X;
+ EC_G_Y = EC224_FP_G_Y;
+ EC_R = EC224_FP_R;
+ EC_K = EC224_FP_K;
+ EC_S = null;
+ break;
+ }
+ case CURVE_secp256r1: {
+ EC_FP_P = EC256_FP_P;
+ EC_A = EC256_FP_A;
+ EC_B = EC256_FP_B;
+ EC_G_X = EC256_FP_G_X;
+ EC_G_Y = EC256_FP_G_Y;
+ EC_R = EC256_FP_R;
+ EC_K = EC256_FP_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_secp384r1: {
+ EC_FP_P = EC384_FP_P;
+ EC_A = EC384_FP_A;
+ EC_B = EC384_FP_B;
+ EC_G_X = EC384_FP_G_X;
+ EC_G_Y = EC384_FP_G_Y;
+ EC_R = EC384_FP_R;
+ EC_K = EC384_FP_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_secp521r1: {
+ EC_FP_P = EC521_FP_P;
+ EC_A = EC521_FP_A;
+ EC_B = EC521_FP_B;
+ EC_G_X = EC521_FP_G_X;
+ EC_G_Y = EC521_FP_G_Y;
+ EC_R = EC521_FP_R;
+ EC_K = EC521_FP_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_sect163r1: {
+ EC_F2M_F2M = EC163_F2M_F;
+ EC_A = EC163_F2M_A;
+ EC_B = EC163_F2M_B;
+ EC_G_X = EC163_F2M_G_X;
+ EC_G_Y = EC163_F2M_G_Y;
+ EC_R = EC163_F2M_R;
+ EC_K = EC163_F2M_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_sect233r1: {
+ EC_F2M_F2M = EC233_F2M_F;
+ EC_A = EC233_F2M_A;
+ EC_B = EC233_F2M_B;
+ EC_G_X = EC233_F2M_G_X;
+ EC_G_Y = EC233_F2M_G_Y;
+ EC_R = EC233_F2M_R;
+ EC_K = EC233_F2M_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_sect283r1: {
+ EC_F2M_F2M = EC283_F2M_F;
+ EC_A = EC283_F2M_A;
+ EC_B = EC283_F2M_B;
+ EC_G_X = EC283_F2M_G_X;
+ EC_G_Y = EC283_F2M_G_Y;
+ EC_R = EC283_F2M_R;
+ EC_K = EC283_F2M_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_sect409r1: {
+ EC_F2M_F2M = EC409_F2M_F;
+ EC_A = EC409_F2M_A;
+ EC_B = EC409_F2M_B;
+ EC_G_X = EC409_F2M_G_X;
+ EC_G_Y = EC409_F2M_G_Y;
+ EC_R = EC409_F2M_R;
+ EC_K = EC409_F2M_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ case CURVE_sect571r1: {
+ EC_F2M_F2M = EC571_F2M_F;
+ EC_A = EC571_F2M_A;
+ EC_B = EC571_F2M_B;
+ EC_G_X = EC571_F2M_G_X;
+ EC_G_Y = EC571_F2M_G_Y;
+ EC_R = EC571_F2M_R;
+ EC_K = EC571_F2M_K;
+ EC_W_X = null;
+ EC_W_Y = null;
+ EC_S = null;
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Unknown curve.");
+ }
+ switch (param) {
+ case PARAMETER_FP:
+ if (alg == ALG_EC_FP) {
+ return EC_FP_P.clone();
+ }
+ break;
+ case PARAMETER_F2M:
+ if (alg == ALG_EC_F2M) {
+ return EC_F2M_F2M.clone();
+ }
+ break;
+ case PARAMETER_A:
+ return EC_A.clone();
+ case PARAMETER_B:
+ return EC_B.clone();
+ case PARAMETER_G:
+ return toX962(X962_UNCOMPRESSED, EC_G_X, EC_G_Y);
+ case PARAMETER_R:
+ return EC_R.clone();
+ case PARAMETER_K:
+ return ByteUtil.shortToBytes(EC_K);
+ case PARAMETER_W:
+ if (EC_W_X == null || EC_W_Y == null) {
+ return null;
+ }
+ return toX962(X962_UNCOMPRESSED, EC_W_X, EC_W_Y);
+ case PARAMETER_S:
+ if (EC_S == null) {
+ return null;
+ }
+ return EC_S.clone();
+ default:
+ throw new IllegalArgumentException("Unknown parameter");
+ }
+ return null;
+ }
+
+ public static byte getCurveType(byte curve) {
+ return curve <= FP_CURVES ? ALG_EC_FP : ALG_EC_F2M;
+ }
+
+ public static byte[] toX962(byte form, byte[] xBuffer, byte[] yBuffer) {
+ ByteBuffer bb = ByteBuffer.allocate(xBuffer.length + yBuffer.length + 1);
+ byte yLSB = yBuffer[yBuffer.length - 1];
+ byte yBit = (byte) (yLSB & 0x01);
+
+ switch (form) {
+ case X962_UNCOMPRESSED:
+ bb.put((byte) 4);
+ break;
+ case X962_HYBRID:
+ if (yBit == 1) {
+ bb.put((byte) 7);
+ } else {
+ bb.put((byte) 6);
+ }
+ break;
+ case X962_COMPRESSED:
+ if (yBit == 1) {
+ bb.put((byte) 3);
+ } else {
+ bb.put((byte) 2);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported form.");
+ }
+ bb.put(xBuffer);
+ if (form == X962_HYBRID || form == X962_UNCOMPRESSED) {
+ bb.put(yBuffer);
+ }
+ return bb.array();
+ }
+
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_Curve.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Curve.java
new file mode 100644
index 0000000..e26fc44
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Curve.java
@@ -0,0 +1,162 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.ByteUtil;
+import org.bouncycastle.math.ec.ECCurve;
+
+import java.math.BigInteger;
+import java.security.spec.*;
+
+/**
+ * An Elliptic curve, contains parameters Fp/F2M, A, B, G, R, (K)?.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Curve extends EC_Params {
+ private short bits;
+ private byte field;
+ private String desc;
+
+ /**
+ * @param bits
+ * @param field EC_Consts.ALG_EC_FP or EC_Consts.ALG_EC_F2M
+ */
+ public EC_Curve(short bits, byte field) {
+ super(field == EC_Consts.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M);
+ this.bits = bits;
+ this.field = field;
+ }
+
+ public EC_Curve(String id, short bits, byte field) {
+ this(bits, field);
+ this.id = id;
+ }
+
+ public EC_Curve(String id, short bits, byte field, String desc) {
+ this(id, bits, field);
+ this.desc = desc;
+ }
+
+ public short getBits() {
+ return bits;
+ }
+
+ public byte getField() {
+ return field;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ @Override
+ public String toString() {
+ return "<" + getId() + "> " + (field == EC_Consts.ALG_EC_FP ? "Prime" : "Binary") + " field Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc) + System.lineSeparator() + super.toString();
+ }
+
+ public EllipticCurve toCurve() {
+ ECField field;
+ if (this.field == EC_Consts.ALG_EC_FP) {
+ field = new ECFieldFp(new BigInteger(1, getData(0)));
+ } else {
+ byte[][] fieldData = getParam(EC_Consts.PARAMETER_F2M);
+ int m = ByteUtil.getShort(fieldData[0], 0);
+ int e1 = ByteUtil.getShort(fieldData[1], 0);
+ int e2 = ByteUtil.getShort(fieldData[2], 0);
+ int e3 = ByteUtil.getShort(fieldData[3], 0);
+ int[] powers;
+ if (e2 == 0 && e3 == 0) {
+ powers = new int[]{e1};
+ } else {
+ powers = new int[]{e1, e2, e3};
+ }
+ field = new ECFieldF2m(m, powers);
+ }
+
+ BigInteger a = new BigInteger(1, getParam(EC_Consts.PARAMETER_A)[0]);
+ BigInteger b = new BigInteger(1, getParam(EC_Consts.PARAMETER_B)[0]);
+
+ return new EllipticCurve(field, a, b);
+ }
+
+ public ECCurve toBCCurve() {
+ if (this.field == EC_Consts.ALG_EC_FP) {
+ BigInteger p = new BigInteger(1, getParam(EC_Consts.PARAMETER_FP)[0]);
+ BigInteger a = new BigInteger(1, getParam(EC_Consts.PARAMETER_A)[0]);
+ BigInteger b = new BigInteger(1, getParam(EC_Consts.PARAMETER_B)[0]);
+ BigInteger r = new BigInteger(1, getParam(EC_Consts.PARAMETER_R)[0]);
+ BigInteger k = new BigInteger(1, getParam(EC_Consts.PARAMETER_K)[0]);
+ return new ECCurve.Fp(p, a, b, r, k);
+ } else {
+ byte[][] fieldData = getParam(EC_Consts.PARAMETER_F2M);
+ int m = ByteUtil.getShort(fieldData[0], 0);
+ int e1 = ByteUtil.getShort(fieldData[1], 0);
+ int e2 = ByteUtil.getShort(fieldData[2], 0);
+ int e3 = ByteUtil.getShort(fieldData[3], 0);
+ BigInteger a = new BigInteger(1, getParam(EC_Consts.PARAMETER_A)[0]);
+ BigInteger b = new BigInteger(1, getParam(EC_Consts.PARAMETER_B)[0]);
+ BigInteger r = new BigInteger(1, getParam(EC_Consts.PARAMETER_R)[0]);
+ BigInteger k = new BigInteger(1, getParam(EC_Consts.PARAMETER_K)[0]);
+ return new ECCurve.F2m(m, e1, e2, e3, a, b, r, k);
+ }
+ }
+
+ public ECParameterSpec toSpec() {
+ EllipticCurve curve = toCurve();
+
+ byte[][] G = getParam(EC_Consts.PARAMETER_G);
+ BigInteger gx = new BigInteger(1, G[0]);
+ BigInteger gy = new BigInteger(1, G[1]);
+ ECPoint generator = new ECPoint(gx, gy);
+
+ BigInteger n = new BigInteger(1, getParam(EC_Consts.PARAMETER_R)[0]);
+
+ int h = ByteUtil.getShortInt(getParam(EC_Consts.PARAMETER_K)[0], 0);
+ return new ECParameterSpec(curve, generator, n, h);
+ }
+
+ public static EC_Curve fromSpec(ECParameterSpec spec) {
+ EllipticCurve curve = spec.getCurve();
+ ECField field = curve.getField();
+
+ short bits = (short) field.getFieldSize();
+ byte[][] params;
+ int paramIndex = 0;
+ byte fieldType;
+ if (field instanceof ECFieldFp) {
+ ECFieldFp primeField = (ECFieldFp) field;
+ params = new byte[7][];
+ params[paramIndex++] = primeField.getP().toByteArray();
+ fieldType = EC_Consts.ALG_EC_FP;
+ } else if (field instanceof ECFieldF2m) {
+ ECFieldF2m binaryField = (ECFieldF2m) field;
+ params = new byte[10][];
+ params[paramIndex] = new byte[2];
+ ByteUtil.setShort(params[paramIndex++], 0, (short) binaryField.getM());
+ int[] powers = binaryField.getMidTermsOfReductionPolynomial();
+ for (int i = 0; i < 3; ++i) {
+ params[paramIndex] = new byte[2];
+ short power = (i < powers.length) ? (short) powers[i] : 0;
+ ByteUtil.setShort(params[paramIndex++], 0, power);
+ }
+ fieldType = EC_Consts.ALG_EC_F2M;
+ } else {
+ throw new IllegalArgumentException("ECParameterSpec with an unknown field.");
+ }
+
+ ECPoint generator = spec.getGenerator();
+
+ params[paramIndex++] = curve.getA().toByteArray();
+ params[paramIndex++] = curve.getB().toByteArray();
+
+ params[paramIndex++] = generator.getAffineX().toByteArray();
+ params[paramIndex++] = generator.getAffineY().toByteArray();
+
+ params[paramIndex++] = spec.getOrder().toByteArray();
+ params[paramIndex] = new byte[2];
+ ByteUtil.setShort(params[paramIndex], 0, (short) spec.getCofactor());
+
+ EC_Curve result = new EC_Curve(bits, fieldType);
+ result.readByteArray(params);
+ return result;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_Data.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Data.java
new file mode 100644
index 0000000..14ae1c5
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Data.java
@@ -0,0 +1,265 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.ByteUtil;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * A list of byte arrays for holding EC data.
+ * <p>
+ * The data can be read from a byte array via <code>readBytes()</code>, from a CSV via <code>readCSV()</code>.
+ * The data can be exported to a byte array via <code>flatten()</code> or to a string array via <code>expand()</code>.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class EC_Data implements Comparable<EC_Data> {
+ String id;
+ int count;
+ byte[][] data;
+
+ private static final Pattern HEX = Pattern.compile("(0x|0X)?[a-fA-F\\d]+");
+
+ EC_Data() {
+ }
+
+ EC_Data(int count) {
+ this.count = count;
+ this.data = new byte[count][];
+ }
+
+ EC_Data(byte[][] data) {
+ this.count = data.length;
+ this.data = data;
+ }
+
+ EC_Data(String id, int count) {
+ this(count);
+ this.id = id;
+ }
+
+ EC_Data(String id, byte[][] data) {
+ this(data);
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public byte[][] getData() {
+ return data;
+ }
+
+ public byte[] getData(int index) {
+ return data[index];
+ }
+
+ public boolean hasData() {
+ return data != null;
+ }
+
+ public byte[] flatten() {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ for (byte[] param : data) {
+ byte[] length = new byte[2];
+ ByteUtil.setShort(length, 0, (short) param.length);
+
+ out.write(length, 0, 2);
+ out.write(param, 0, param.length);
+ }
+
+ return out.toByteArray();
+ }
+
+ public String[] expand() {
+ List<String> out = new ArrayList<>(count);
+ for (byte[] param : data) {
+ out.add(ByteUtil.bytesToHex(param, false));
+ }
+
+ return out.toArray(new String[out.size()]);
+ }
+
+ private static byte[] pad(byte[] data) {
+ if (data.length == 1) {
+ return new byte[]{(byte) 0, data[0]};
+ } else if (data.length == 0 || data.length > 2) {
+ return data;
+ }
+ return null;
+ }
+
+ protected static byte[] parse(String param) {
+ byte[] data;
+ if (param.startsWith("0x") || param.startsWith("0X")) {
+ data = ByteUtil.hexToBytes(param.substring(2));
+ } else {
+ data = ByteUtil.hexToBytes(param);
+ }
+ if (data == null)
+ return new byte[0];
+ if (data.length < 2)
+ return pad(data);
+ return data;
+ }
+
+ private boolean readHex(String[] hex) {
+ if (hex.length != count) {
+ return false;
+ }
+
+ for (int i = 0; i < count; ++i) {
+ this.data[i] = parse(hex[i]);
+ }
+ return true;
+ }
+
+ public boolean readCSV(InputStream in) {
+ Scanner s = new Scanner(in);
+
+ s.useDelimiter("[,;]");
+ List<String> data = new LinkedList<>();
+ while (s.hasNext()) {
+ String field = s.next();
+ data.add(field.replaceAll("\\s+", ""));
+ }
+
+ if (data.isEmpty()) {
+ return false;
+ }
+ for (String param : data) {
+ if (!HEX.matcher(param).matches()) {
+ return false;
+ }
+ }
+ return readHex(data.toArray(new String[data.size()]));
+ }
+
+ public boolean readBytes(byte[] bytes) {
+ if (bytes == null) {
+ return false;
+ }
+
+ int offset = 0;
+ for (int i = 0; i < count; i++) {
+ if (bytes.length - offset < 2) {
+ return false;
+ }
+ short paramLength = ByteUtil.getShort(bytes, offset);
+ offset += 2;
+ if (bytes.length < offset + paramLength) {
+ return false;
+ }
+ data[i] = new byte[paramLength];
+ System.arraycopy(bytes, offset, data[i], 0, paramLength);
+ offset += paramLength;
+ }
+ return true;
+ }
+
+ public boolean readByteArray(byte[][] bytes) {
+ if (bytes == null || count != bytes.length) {
+ return false;
+ }
+
+ for (int i = 0; i < count; ++i) {
+ data[i] = new byte[bytes[i].length];
+ System.arraycopy(bytes[i], 0, data[i], 0, bytes[i].length);
+ }
+ return true;
+ }
+
+ public void writeCSV(OutputStream out) throws IOException {
+ Writer w = new OutputStreamWriter(out);
+ w.write(String.join(",", expand()));
+ w.flush();
+ }
+
+ @Override
+ public String toString() {
+ return String.join(",", expand());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof EC_Data) {
+ EC_Data other = (EC_Data) obj;
+ if (this.id != null || other.id != null) {
+ return Objects.equals(this.id, other.id);
+ }
+
+ if (this.count != other.count)
+ return false;
+ for (int i = 0; i < this.count; ++i) {
+ if (!Arrays.equals(this.data[i], other.data[i])) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ if (this.id != null) {
+ return this.id.hashCode();
+ }
+ return Arrays.deepHashCode(this.data);
+ }
+
+ @Override
+ public int compareTo(EC_Data o) {
+ if (o == this) return 0;
+ if (this.id != null && o.id != null) {
+
+ int minLength = Math.min(this.id.length(), o.id.length());
+ for (int i = 0; i < minLength; i++) {
+ if (this.id.charAt(i) != o.id.charAt(i)) {
+ String thisEnd = this.id.substring(i);
+ String oEnd = o.id.substring(i);
+ try {
+ int thisIndex = Integer.parseInt(thisEnd);
+ int oIndex = Integer.parseInt(oEnd);
+ return Integer.compare(thisIndex, oIndex);
+ } catch (NumberFormatException ignored) {
+ break;
+ }
+ }
+ }
+ return this.id.compareTo(o.id);
+ } else if (this.id == null && o.id == null) {
+ if (Arrays.equals(this.data, o.data)) {
+ return 0;
+ } else {
+ int minCount = (this.count < o.count) ? this.count : o.count;
+ for (int i = 0; i < minCount; ++i) {
+ byte[] thisData = this.data[i];
+ byte[] oData = o.data[i];
+ int innerMinCount = (thisData.length < oData.length) ? thisData.length : oData.length;
+ for (int j = 0; j < innerMinCount; ++j) {
+ if (thisData[j] < oData[j]) {
+ return -1;
+ } else if (thisData[j] > oData[j]) {
+ return 1;
+ }
+ }
+ }
+ }
+ } else {
+ if (this.id == null) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_KAResult.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_KAResult.java
new file mode 100644
index 0000000..4e97950
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_KAResult.java
@@ -0,0 +1,65 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.CardUtil;
+
+/**
+ * A result of EC based Key agreement operation.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_KAResult extends EC_Data {
+ private String ka;
+ private String curve;
+ private String oneKey;
+ private String otherKey;
+
+ private String desc;
+
+ public EC_KAResult(String ka, String curve, String oneKey, String otherKey) {
+ super(1);
+ this.ka = ka;
+ this.curve = curve;
+ this.oneKey = oneKey;
+ this.otherKey = otherKey;
+ }
+
+ public EC_KAResult(String id, String ka, String curve, String oneKey, String otherKey) {
+ this(ka, curve, oneKey, otherKey);
+ this.id = id;
+ }
+
+ public EC_KAResult(String id, String ka, String curve, String oneKey, String otherKey, String desc) {
+ this(id, ka, curve, oneKey, otherKey);
+ this.desc = desc;
+ }
+
+ public String getKA() {
+ return ka;
+ }
+
+ public byte getJavaCardKA() {
+ return CardUtil.getKA(ka);
+ }
+
+ public String getCurve() {
+ return curve;
+ }
+
+ public String getOneKey() {
+ return oneKey;
+ }
+
+ public String getOtherKey() {
+ return otherKey;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ @Override
+ public String toString() {
+ return "<" + getId() + "> " + ka + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc) + System.lineSeparator() + super.toString();
+ }
+
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_Key.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Key.java
new file mode 100644
index 0000000..a9f0c40
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Key.java
@@ -0,0 +1,81 @@
+package cz.crcs.ectester.common.ec;
+
+/**
+ * An abstract-like EC key. Concrete implementations create a public and private keys.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Key extends EC_Params {
+
+ private String curve;
+ private String desc;
+
+ private EC_Key(short mask, String curve) {
+ super(mask);
+ this.curve = curve;
+ }
+
+ private EC_Key(short mask, String curve, String desc) {
+ this(mask, curve);
+ this.desc = desc;
+ }
+
+ private EC_Key(String id, short mask, String curve, String desc) {
+ this(mask, curve, desc);
+ this.id = id;
+ }
+
+ public String getCurve() {
+ return curve;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ /**
+ * An EC public key, contains the W parameter.
+ */
+ public static class Public extends EC_Key {
+
+ public Public(String curve) {
+ super(EC_Consts.PARAMETER_W, curve);
+ }
+
+ public Public(String curve, String desc) {
+ super(EC_Consts.PARAMETER_W, curve, desc);
+ }
+
+ public Public(String id, String curve, String desc) {
+ super(id, EC_Consts.PARAMETER_W, curve, desc);
+ }
+
+ @Override
+ public String toString() {
+ return "<" + getId() + "> EC Public key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()) + System.lineSeparator() + super.toString();
+ }
+ }
+
+ /**
+ * An EC private key, contains the S parameter.
+ */
+ public static class Private extends EC_Key {
+
+ public Private(String curve) {
+ super(EC_Consts.PARAMETER_S, curve);
+ }
+
+ public Private(String curve, String desc) {
+ super(EC_Consts.PARAMETER_S, curve, desc);
+ }
+
+ public Private(String id, String curve, String desc) {
+ super(id, EC_Consts.PARAMETER_S, curve, desc);
+ }
+
+ @Override
+ public String toString() {
+ return "<" + getId() + "> EC Private key, over " + getCurve() + (getDesc() == null ? "" : ": " + getDesc()) + System.lineSeparator() + super.toString();
+ }
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_Keypair.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Keypair.java
new file mode 100644
index 0000000..b1a0cbc
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Keypair.java
@@ -0,0 +1,39 @@
+package cz.crcs.ectester.common.ec;
+
+/**
+ * An EC keypair, contains both the W and S parameters.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Keypair extends EC_Params {
+ private String curve;
+ private String desc;
+
+ public EC_Keypair(String curve) {
+ super(EC_Consts.PARAMETERS_KEYPAIR);
+ this.curve = curve;
+ }
+
+ public EC_Keypair(String curve, String desc) {
+ this(curve);
+ this.desc = desc;
+ }
+
+ public EC_Keypair(String id, String curve, String desc) {
+ this(curve, desc);
+ this.id = id;
+ }
+
+ public String getCurve() {
+ return curve;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ @Override
+ public String toString() {
+ return "<" + getId() + "> EC Keypair, over " + curve + (desc == null ? "" : ": " + desc) + System.lineSeparator() + super.toString();
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_Params.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Params.java
new file mode 100644
index 0000000..146c8d6
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_Params.java
@@ -0,0 +1,233 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.ByteUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A list of EC parameters, can contain a subset of the Fp/F2M, A, B, G, R, K, W, S parameters.
+ * <p>
+ * The set of parameters is uniquely identified by a short bit string.
+ * The parameters can be exported to a byte array via <code>flatten()</code> or to a comma delimited
+ * string via <code>expand()</code>.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Params extends EC_Data {
+ private short params;
+
+ public EC_Params(short params) {
+ this.params = params;
+ this.count = numParams();
+ this.data = new byte[this.count][];
+ }
+
+ public EC_Params(short params, byte[][] data) {
+ this.params = params;
+ this.count = data.length;
+ this.data = data;
+ }
+
+ public EC_Params(String id, short params) {
+ this(params);
+ this.id = id;
+ }
+
+ public EC_Params(String id, short params, byte[][] data) {
+ this(params, data);
+ this.id = id;
+ }
+
+ public short getParams() {
+ return params;
+ }
+
+ public byte[][] getParam(short param) {
+ if (!hasParam(param)) {
+ return null;
+ }
+ if (Integer.bitCount(param) != 1) {
+ return null;
+ }
+ short paramMask = EC_Consts.PARAMETER_FP;
+ byte[][] result = null;
+ int i = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (this.params & param & paramMask);
+ short shallow = (short) (this.params & paramMask);
+ if (masked != 0) {
+ if (masked == EC_Consts.PARAMETER_F2M) {
+ result = new byte[4][];
+ result[0] = data[i].clone();
+ result[1] = data[i + 1].clone();
+ result[2] = data[i + 2].clone();
+ result[3] = data[i + 3].clone();
+ break;
+ }
+ if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
+ result = new byte[2][];
+ result[0] = data[i].clone();
+ result[1] = data[i + 1].clone();
+ break;
+ }
+ result = new byte[1][];
+ result[0] = data[i].clone();
+ }
+ if (shallow == EC_Consts.PARAMETER_F2M) {
+ i += 4;
+ } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) {
+ i += 2;
+ } else if (shallow != 0) {
+ i++;
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+ return result;
+ }
+
+ public boolean setParam(short param, byte[][] value) {
+ if (!hasParam(param)) {
+ return false;
+ }
+ if (Integer.bitCount(param) != 1) {
+ return false;
+ }
+ short paramMask = EC_Consts.PARAMETER_FP;
+ int i = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (this.params & param & paramMask);
+ short shallow = (short) (this.params & paramMask);
+ if (masked != 0) {
+ if (masked == EC_Consts.PARAMETER_F2M) {
+ data[i] = value[0];
+ data[i + 1] = value[1];
+ data[i + 2] = value[2];
+ data[i + 3] = value[3];
+ break;
+ }
+ if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
+ data[i] = value[0];
+ data[i + 1] = value[1];
+ break;
+ }
+ data[i] = value[0];
+ }
+ if (shallow == EC_Consts.PARAMETER_F2M) {
+ i += 4;
+ } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) {
+ i += 2;
+ } else if (shallow != 0) {
+ i++;
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+ return true;
+ }
+
+ public boolean hasParam(short param) {
+ return (params & param) != 0;
+ }
+
+ public int numParams() {
+ short paramMask = EC_Consts.PARAMETER_FP;
+ int num = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ if ((paramMask & params) != 0) {
+ if (paramMask == EC_Consts.PARAMETER_F2M) {
+ num += 3;
+ }
+ if (paramMask == EC_Consts.PARAMETER_W || paramMask == EC_Consts.PARAMETER_G) {
+ num += 1;
+ }
+ ++num;
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+ return num;
+ }
+
+ @Override
+ public byte[] flatten() {
+ return flatten(params);
+ }
+
+ public byte[] flatten(short params) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ short paramMask = EC_Consts.PARAMETER_FP;
+ int i = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (this.params & params & paramMask);
+ short shallow = (short) (this.params & paramMask);
+ if (masked != 0) {
+ byte[] param = data[i];
+ if (masked == EC_Consts.PARAMETER_F2M) {
+ //add m, e_1, e_2, e_3
+ param = ByteUtil.concatenate(param, data[i + 1]);
+ if (!ByteUtil.allValue(data[i + 2], (byte) 0)) {
+ param = ByteUtil.concatenate(param, data[i + 2]);
+ }
+ if (!ByteUtil.allValue(data[i + 3], (byte) 0)) {
+ param = ByteUtil.concatenate(param, data[i + 3]);
+ }
+ if (!(param.length == 4 || param.length == 8))
+ throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)");
+ }
+ if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
+ //read another param (the y coord) and put into X962 format.
+ byte[] y = data[i + 1];
+ param = ByteUtil.concatenate(new byte[]{4}, param, y); //<- ugly but works!
+ }
+ if (param.length == 0)
+ throw new RuntimeException("Empty parameter read?");
+
+ //write length
+ byte[] length = new byte[2];
+ ByteUtil.setShort(length, 0, (short) param.length);
+ out.write(length, 0, 2);
+ //write data
+ out.write(param, 0, param.length);
+ }
+ if (shallow == EC_Consts.PARAMETER_F2M) {
+ i += 4;
+ } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) {
+ i += 2;
+ } else if (shallow != 0) {
+ i++;
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+
+ return (out.size() == 0) ? null : out.toByteArray();
+ }
+
+ @Override
+ public String[] expand() {
+ List<String> out = new ArrayList<>();
+
+ short paramMask = EC_Consts.PARAMETER_FP;
+ int index = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short masked = (short) (params & paramMask);
+ if (masked != 0) {
+ byte[] param = data[index];
+ if (masked == EC_Consts.PARAMETER_F2M) {
+ for (int i = 0; i < 4; ++i) {
+ out.add(ByteUtil.bytesToHex(data[index + i], false));
+ }
+ index += 4;
+ } else if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
+ out.add(ByteUtil.bytesToHex(param, false));
+ out.add(ByteUtil.bytesToHex(data[index + 1], false));
+ index += 2;
+ } else {
+ out.add(ByteUtil.bytesToHex(param, false));
+ index++;
+ }
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+ return out.toArray(new String[0]);
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/EC_SigResult.java b/common/src/main/java/cz/crcs/ectester/common/ec/EC_SigResult.java
new file mode 100644
index 0000000..d97ced1
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/EC_SigResult.java
@@ -0,0 +1,75 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.CardUtil;
+
+/**
+ * A result of EC based Signature operation.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_SigResult extends EC_Data {
+ private String sig;
+ private String curve;
+ private String signKey;
+ private String verifyKey;
+
+ private String data;
+ private String desc;
+
+ public EC_SigResult(String sig, String curve, String signKey, String verifyKey, String raw) {
+ super(1);
+ this.sig = sig;
+ this.curve = curve;
+ this.signKey = signKey;
+ this.verifyKey = verifyKey;
+ this.data = raw;
+ }
+
+ public EC_SigResult(String id, String sig, String curve, String signKey, String verifyKey, String data) {
+ this(sig, curve, signKey, verifyKey, data);
+ this.id = id;
+ }
+
+ public EC_SigResult(String id, String sig, String curve, String signKey, String verifyKey, String data, String desc) {
+ this(id, sig, curve, signKey, verifyKey, data);
+ this.desc = desc;
+ }
+
+ public String getSig() {
+ return sig;
+ }
+
+ public byte getJavaCardSig() {
+ return CardUtil.getSig(sig);
+ }
+
+ public String getCurve() {
+ return curve;
+ }
+
+ public String getSignKey() {
+ return signKey;
+ }
+
+ public String getVerifyKey() {
+ return verifyKey;
+ }
+
+ public byte[] getSigData() {
+ if (data == null) {
+ return null;
+ } else {
+ return parse(data);
+ }
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ @Override
+ public String toString() {
+ return "<" + getId() + "> " + sig + " result over " + curve + ", " + signKey + " + " + verifyKey + (data == null ? "" : " of data \"" + data + "\"") + (desc == null ? "" : ": " + desc) + System.lineSeparator() + super.toString();
+ }
+
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/RawECPrivateKey.java b/common/src/main/java/cz/crcs/ectester/common/ec/RawECPrivateKey.java
new file mode 100644
index 0000000..479118f
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/RawECPrivateKey.java
@@ -0,0 +1,46 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public class RawECPrivateKey implements ECPrivateKey {
+ private BigInteger scalar;
+ private ECParameterSpec params;
+
+ public RawECPrivateKey(BigInteger scalar, ECParameterSpec params) {
+ this.scalar = scalar;
+ this.params = params;
+ }
+
+ @Override
+ public BigInteger getS() {
+ return scalar;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "EC";
+ }
+
+ @Override
+ public String getFormat() {
+ return "Raw";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return ECUtil.toByteArray(scalar, params.getOrder().bitLength());
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/ec/RawECPublicKey.java b/common/src/main/java/cz/crcs/ectester/common/ec/RawECPublicKey.java
new file mode 100644
index 0000000..7888854
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/ec/RawECPublicKey.java
@@ -0,0 +1,46 @@
+package cz.crcs.ectester.common.ec;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public class RawECPublicKey implements ECPublicKey {
+ private ECPoint point;
+ private ECParameterSpec params;
+
+ public RawECPublicKey(ECPoint point, ECParameterSpec params) {
+ this.point = point;
+ this.params = params;
+ }
+
+ @Override
+ public ECPoint getW() {
+ return point;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "EC";
+ }
+
+ @Override
+ public String getFormat() {
+ return "Raw";
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return ECUtil.toX962Uncompressed(point, params);
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/common/src/main/java/cz/crcs/ectester/common/output/BaseTextTestWriter.java
new file mode 100644
index 0000000..5c449db
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/output/BaseTextTestWriter.java
@@ -0,0 +1,149 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.cli.Colors;
+import cz.crcs.ectester.common.test.*;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * An absctract basis of a TextTestWriter, which outputs in a human readable format, into console.
+ * Requires the implementation of:
+ * <code>String testableString(Testable t)</code>
+ * <code>String deviceString(TestSuite t)</code>
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseTextTestWriter implements TestWriter {
+ private PrintStream output;
+
+ public static int BASE_WIDTH = 105;
+
+ public BaseTextTestWriter(PrintStream output) {
+ this.output = output;
+ }
+
+ @Override
+ public void begin(TestSuite suite) {
+ output.println("═══ " + Colors.underline("Running test suite:") + " " + Colors.bold(suite.getName()) + " ═══");
+ for (String d : suite.getDescription()) {
+ output.println("═══ " + d);
+ }
+ DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
+ Date date = new Date();
+ output.println("═══ " + Colors.underline("Date:") + " " + dateFormat.format(date));
+ output.print(deviceString(suite));
+ }
+
+ /**
+ * @param t
+ * @return
+ */
+ protected abstract String testableString(Testable t);
+
+ /**
+ * @param suite
+ * @return
+ */
+ protected abstract String deviceString(TestSuite suite);
+
+ private String testString(Test t, String prefix, int index) {
+ boolean compound = t instanceof CompoundTest;
+
+ Result result = t.getResult();
+
+ String line = "";
+ if (prefix.equals("")) {
+ char[] charLine = new char[BASE_WIDTH + 24];
+ new String(new char[BASE_WIDTH + 24]).replace("\0", "━").getChars(0, charLine.length - 1, charLine, 0);
+ charLine[0] = '■';
+ charLine[4] = '┳';
+ charLine[BASE_WIDTH + 1] = '┳';
+ charLine[BASE_WIDTH + 13] = '┳';
+ charLine[BASE_WIDTH + 23] = '┓';
+ line = new String(charLine) + System.lineSeparator();
+ }
+
+ StringBuilder out = new StringBuilder();
+ out.append(t.ok() ? Colors.ok(" OK ") : Colors.error("NOK "));
+ out.append(compound ? (prefix.equals("") ? "╋ " : "┳ ") : "━ ");
+ int width = BASE_WIDTH - (prefix.length() + 6);
+ String widthSpec = "%-" + width + "s";
+ String desc = ((prefix.equals("")) ? "(" + index + ") " : "") + t.getDescription();
+ out.append(String.format(widthSpec, desc));
+ out.append(" ┃ ");
+ Colors.Foreground valueColor;
+ if (result.getValue().ok()) {
+ valueColor = Colors.Foreground.GREEN;
+ } else if (result.getValue().equals(Result.Value.ERROR)) {
+ valueColor = Colors.Foreground.RED;
+ } else {
+ valueColor = Colors.Foreground.YELLOW;
+ }
+ out.append(Colors.colored(String.format("%-9s", result.getValue().name()), Colors.Attribute.BOLD, valueColor));
+ out.append(" ┃ ");
+
+ if (compound) {
+ CompoundTest test = (CompoundTest) t;
+ out.append(result.getCause());
+ out.append(System.lineSeparator());
+ Test[] tests = test.getStartedTests();
+ for (int i = 0; i < tests.length; ++i) {
+ if (i == tests.length - 1) {
+ out.append(prefix).append(" ┗ ");
+ out.append(testString(tests[i], prefix + " ", index));
+ } else {
+ out.append(prefix).append(" ┣ ");
+ out.append(testString(tests[i], prefix + " ┃ ", index));
+ }
+
+ if (i != tests.length - 1) {
+ out.append(System.lineSeparator());
+ }
+ }
+ } else {
+ SimpleTest<? extends BaseTestable> test = (SimpleTest<? extends BaseTestable>) t;
+ out.append(testableString(test.getTestable()));
+ if (t.getResult().getCause() != null) {
+ out.append(" ┃ ").append(t.getResult().getCause().toString());
+ }
+ }
+ return line + out.toString();
+ }
+
+ @Override
+ public void outputTest(Test t, int index) {
+ if (!t.hasRun())
+ return;
+ output.println(testString(t, "", index));
+ output.flush();
+ }
+
+ private String errorString(Throwable error) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("═══ Exception: ═══").append(System.lineSeparator());
+ for (Throwable t = error; t != null; t = t.getCause()) {
+ sb.append("═══ ").append(t.toString()).append(" ═══");
+ sb.append(System.lineSeparator());
+ }
+ sb.append("═══ Stack trace: ═══").append(System.lineSeparator());
+ for (StackTraceElement s : error.getStackTrace()) {
+ sb.append("═══ ").append(s.toString()).append(" ═══");
+ sb.append(System.lineSeparator());
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void outputError(Test t, Throwable cause, int index) {
+ output.println(testString(t, "", index));
+ output.print(errorString(cause));
+ output.flush();
+ }
+
+ @Override
+ public void end() {
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/output/BaseXMLTestWriter.java b/common/src/main/java/cz/crcs/ectester/common/output/BaseXMLTestWriter.java
new file mode 100644
index 0000000..53970dd
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/output/BaseXMLTestWriter.java
@@ -0,0 +1,144 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.test.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseXMLTestWriter implements TestWriter {
+ private OutputStream output;
+ private DocumentBuilder db;
+ protected Document doc;
+ private Node root;
+ private Node tests;
+
+ public BaseXMLTestWriter(OutputStream output) throws ParserConfigurationException {
+ this.output = output;
+ this.db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ }
+
+ @Override
+ public void begin(TestSuite suite) {
+ doc = db.newDocument();
+ Element rootElem = doc.createElement("testSuite");
+ rootElem.setAttribute("name", suite.getName());
+ rootElem.setAttribute("desc", suite.getTextDescription());
+ DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
+ Date date = new Date();
+ rootElem.setAttribute("date", dateFormat.format(date));
+
+ root = rootElem;
+ doc.appendChild(root);
+ root.appendChild(deviceElement(suite));
+ tests = doc.createElement("tests");
+ root.appendChild(tests);
+ }
+
+ protected abstract Element testableElement(Testable t);
+
+ protected abstract Element deviceElement(TestSuite suite);
+
+ private String causeString(Object cause) {
+ if (cause == null) {
+ return "null";
+ } else if (cause instanceof Throwable) {
+ StringBuilder sb = new StringBuilder();
+ for (Throwable t = (Throwable) cause; t != null; t = t.getCause()) {
+ sb.append(t.toString());
+ sb.append(System.lineSeparator());
+ }
+ return sb.toString();
+ } else {
+ return cause.toString();
+ }
+ }
+
+ private Element resultElement(Result result) {
+ Element resultElem = doc.createElement("result");
+
+ Element ok = doc.createElement("ok");
+ ok.setTextContent(String.valueOf(result.ok()));
+ Element value = doc.createElement("value");
+ value.setTextContent(result.getValue().name());
+ Element cause = doc.createElement("cause");
+ cause.setTextContent(causeString(result.getCause()));
+
+ resultElem.appendChild(ok);
+ resultElem.appendChild(value);
+ resultElem.appendChild(cause);
+
+ return resultElem;
+ }
+
+ private Element testElement(Test t, int index) {
+ Element testElem;
+ if (t instanceof CompoundTest) {
+ CompoundTest test = (CompoundTest) t;
+ testElem = doc.createElement("test");
+ testElem.setAttribute("type", "compound");
+ for (Test innerTest : test.getStartedTests()) {
+ testElem.appendChild(testElement(innerTest, -1));
+ }
+ } else {
+ SimpleTest<? extends BaseTestable> test = (SimpleTest<? extends BaseTestable>) t;
+ testElem = testableElement(test.getTestable());
+ }
+
+ Element description = doc.createElement("desc");
+ description.setTextContent(t.getDescription());
+ testElem.appendChild(description);
+
+ Element result = resultElement(t.getResult());
+ testElem.appendChild(result);
+
+ if (index != -1) {
+ testElem.setAttribute("index", String.valueOf(index));
+ }
+
+ return testElem;
+ }
+
+ @Override
+ public void outputTest(Test t, int index) {
+ if (!t.hasRun())
+ return;
+ tests.appendChild(testElement(t, index));
+ }
+
+ @Override
+ public void outputError(Test t, Throwable cause, int index) {
+ tests.appendChild(testElement(t, index));
+ }
+
+ @Override
+ public void end() {
+ try {
+ DOMSource domSource = new DOMSource(doc);
+ StreamResult result = new StreamResult(output);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+ transformer.transform(domSource, result);
+ } catch (TransformerException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java b/common/src/main/java/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java
new file mode 100644
index 0000000..e054563
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java
@@ -0,0 +1,120 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.test.*;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseYAMLTestWriter implements TestWriter {
+ private PrintStream output;
+ private Map<String, Object> testRun;
+ private Map<String, String> testSuite;
+ protected List<Object> tests;
+
+ public BaseYAMLTestWriter(PrintStream output) {
+ this.output = output;
+ }
+
+ @Override
+ public void begin(TestSuite suite) {
+ output.println("---");
+ testRun = new LinkedHashMap<>();
+ testSuite = new LinkedHashMap<>();
+ tests = new LinkedList<>();
+ testSuite.put("name", suite.getName());
+ testSuite.put("desc", suite.getTextDescription());
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
+ Date date = new Date();
+ testRun.put("date", dateFormat.format(date));
+ testRun.put("suite", testSuite);
+ testRun.put("device", deviceObject(suite));
+ testRun.put("tests", tests);
+ }
+
+ abstract protected Map<String, Object> testableObject(Testable t);
+
+ abstract protected Map<String, Object> deviceObject(TestSuite suite);
+
+ private Object causeObject(Object cause) {
+ if (cause == null) {
+ return null;
+ } else if (cause instanceof Throwable) {
+ StringBuilder sb = new StringBuilder();
+ for (Throwable t = (Throwable) cause; t != null; t = t.getCause()) {
+ sb.append(t.toString());
+ sb.append(System.lineSeparator());
+ }
+ return sb.toString();
+ } else {
+ return cause.toString();
+ }
+ }
+
+ private Map<String, Object> resultObject(Result result) {
+ Map<String, Object> resultObject = new LinkedHashMap<>();
+ resultObject.put("ok", result.ok());
+ resultObject.put("value", result.getValue().name());
+ resultObject.put("cause", causeObject(result.getCause()));
+ return resultObject;
+ }
+
+ private Map<String, Object> testObject(Test t, int index) {
+ Map<String, Object> testObj;
+ if (t instanceof CompoundTest) {
+ CompoundTest test = (CompoundTest) t;
+ testObj = new HashMap<>();
+ testObj.put("type", "compound");
+ List<Map<String, Object>> innerTests = new LinkedList<>();
+ for (Test innerTest : test.getStartedTests()) {
+ innerTests.add(testObject(innerTest, -1));
+ }
+ testObj.put("tests", innerTests);
+ } else {
+ SimpleTest<? extends BaseTestable> test = (SimpleTest<? extends BaseTestable>) t;
+ testObj = testableObject(test.getTestable());
+ }
+
+ testObj.put("desc", t.getDescription());
+ testObj.put("result", resultObject(t.getResult()));
+ if (index != -1) {
+ testObj.put("index", index);
+ }
+
+ return testObj;
+ }
+
+ @Override
+ public void outputTest(Test t, int index) {
+ if (!t.hasRun())
+ return;
+ tests.add(testObject(t, index));
+ }
+
+ @Override
+ public void outputError(Test t, Throwable cause, int index) {
+ tests.add(testObject(t, index));
+ }
+
+ @Override
+ public void end() {
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ options.setPrettyFlow(true);
+ Yaml yaml = new Yaml(options);
+
+ Map<String, Object> result = new LinkedHashMap<>();
+ result.put("testRun", testRun);
+ String out = yaml.dump(result);
+
+ output.println(out);
+ output.println("---");
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/output/OutputLogger.java b/common/src/main/java/cz/crcs/ectester/common/output/OutputLogger.java
new file mode 100644
index 0000000..effd1fd
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/output/OutputLogger.java
@@ -0,0 +1,63 @@
+package cz.crcs.ectester.common.output;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class OutputLogger {
+ private OutputStream out;
+ private PrintStream print;
+
+ public OutputLogger(boolean systemOut, String... filePaths) throws IOException {
+ List<OutputStream> streams = new LinkedList<>();
+ for (String filePath : filePaths) {
+ if (filePath != null) {
+ streams.add(new FileOutputStream(filePath));
+ }
+ }
+ if (systemOut) {
+ streams.add(System.out);
+ }
+ this.out = new TeeOutputStream(streams.toArray(new OutputStream[0]));
+ this.print = new PrintStream(this.out);
+ }
+
+ public OutputLogger(String filePath) throws IOException {
+ this(true, filePath);
+ }
+
+ public OutputStream getOutputStream() {
+ return this.out;
+ }
+
+ public PrintStream getPrintStream() {
+ return this.print;
+ }
+
+ public void println() {
+ print.println();
+ }
+
+ public void println(String logLine) {
+ print.println(logLine);
+ }
+
+ public void print(String logLine) {
+ print.print(logLine);
+ }
+
+ public void flush() {
+ print.flush();
+ }
+
+ public void close() {
+ print.close();
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/output/TeeOutputStream.java b/common/src/main/java/cz/crcs/ectester/common/output/TeeOutputStream.java
new file mode 100644
index 0000000..2401fce
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/output/TeeOutputStream.java
@@ -0,0 +1,36 @@
+package cz.crcs.ectester.common.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TeeOutputStream extends OutputStream {
+ private OutputStream[] outputs;
+
+ public TeeOutputStream(OutputStream... outputs) {
+ this.outputs = outputs;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ for (OutputStream out : outputs) {
+ out.write(b);
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ for (OutputStream out : outputs) {
+ out.flush();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ for (OutputStream out : outputs) {
+ out.close();
+ }
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/output/TeeTestWriter.java b/common/src/main/java/cz/crcs/ectester/common/output/TeeTestWriter.java
new file mode 100644
index 0000000..58a0a15
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/output/TeeTestWriter.java
@@ -0,0 +1,43 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.test.TestSuite;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TeeTestWriter implements TestWriter {
+ protected TestWriter[] writers;
+
+ public TeeTestWriter(TestWriter... writers) {
+ this.writers = writers;
+ }
+
+ @Override
+ public void begin(TestSuite suite) {
+ for (TestWriter writer : writers) {
+ writer.begin(suite);
+ }
+ }
+
+ @Override
+ public void outputTest(Test t, int index) {
+ for (TestWriter writer : writers) {
+ writer.outputTest(t, index);
+ }
+ }
+
+ @Override
+ public void outputError(Test t, Throwable cause, int index) {
+ for (TestWriter writer : writers) {
+ writer.outputError(t, cause, index);
+ }
+ }
+
+ @Override
+ public void end() {
+ for (TestWriter writer : writers) {
+ writer.end();
+ }
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/output/TestWriter.java b/common/src/main/java/cz/crcs/ectester/common/output/TestWriter.java
new file mode 100644
index 0000000..67aeccb
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/output/TestWriter.java
@@ -0,0 +1,38 @@
+package cz.crcs.ectester.common.output;
+
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.test.TestSuite;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public interface TestWriter {
+ /**
+ * Begin writing the <code>TestSuite suite</code>.
+ * This should reset all the internal state of the writer
+ * and prepare it to output tests from <code>suite</code>.
+ * It may also write any header part of the output of the
+ * writer but doesn't have to.
+ *
+ * @param suite The <code>TestSuite</code> to start writing.
+ */
+ void begin(TestSuite suite);
+
+ /**
+ * @param t
+ * @param index
+ */
+ void outputTest(Test t, int index);
+
+ /**
+ * @param t
+ * @param cause
+ * @param index
+ */
+ void outputError(Test t, Throwable cause, int index);
+
+ /**
+ *
+ */
+ void end();
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/BaseTestable.java b/common/src/main/java/cz/crcs/ectester/common/test/BaseTestable.java
new file mode 100644
index 0000000..3c304d9
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/BaseTestable.java
@@ -0,0 +1,44 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class BaseTestable implements Testable, Cloneable {
+ protected boolean hasRun;
+ protected boolean ok;
+ protected boolean error;
+ protected Object errorCause;
+
+ @Override
+ public boolean hasRun() {
+ return hasRun;
+ }
+
+ @Override
+ public boolean ok() {
+ return ok;
+ }
+
+ @Override
+ public boolean error() {
+ return error;
+ }
+
+ @Override
+ public Object errorCause() {
+ return errorCause;
+ }
+
+ @Override
+ public void reset() {
+ hasRun = false;
+ ok = false;
+ error = false;
+ errorCause = null;
+ }
+
+ @Override
+ protected BaseTestable clone() throws CloneNotSupportedException {
+ return (BaseTestable) super.clone();
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/CompoundTest.java b/common/src/main/java/cz/crcs/ectester/common/test/CompoundTest.java
new file mode 100644
index 0000000..ba4ad4f
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/CompoundTest.java
@@ -0,0 +1,214 @@
+package cz.crcs.ectester.common.test;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A compound test that runs many Tests and has a Result dependent on all/some of their Results.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CompoundTest extends Test implements Cloneable {
+ private Function<Test[], Result> resultCallback;
+ private Consumer<Test[]> runCallback;
+ private Test[] tests;
+ private String description = "";
+
+ private final static Consumer<Test[]> RUN_ALL = tests -> {
+ for (Test t : tests) {
+ t.run();
+ }
+ };
+
+ private final static Consumer<Test[]> RUN_GREEDY_ALL = tests -> {
+ for (Test t : tests) {
+ t.run();
+ if (!t.ok()) {
+ break;
+ }
+ }
+ };
+
+ private final static Consumer<Test[]> RUN_GREEDY_ANY = tests -> {
+ for (Test t : tests) {
+ t.run();
+ if (t.ok()) {
+ break;
+ }
+ }
+ };
+
+ private CompoundTest(Function<Test[], Result> resultCallback, Consumer<Test[]> runCallback, Test... tests) {
+ this.resultCallback = resultCallback;
+ this.runCallback = runCallback;
+ this.tests = Arrays.stream(tests).filter(Objects::nonNull).toArray(Test[]::new);
+ }
+
+ private CompoundTest(Function<Test[], Result> callback, Consumer<Test[]> runCallback, String descripiton, Test... tests) {
+ this(callback, runCallback, tests);
+ this.description = descripiton;
+ }
+
+ public static CompoundTest function(Function<Test[], Result> callback, Test... tests) {
+ return new CompoundTest(callback, RUN_ALL, tests);
+ }
+
+ public static CompoundTest function(Function<Test[], Result> callback, Consumer<Test[]> runCallback, Test... tests) {
+ return new CompoundTest(callback, runCallback, tests);
+ }
+
+ public static CompoundTest function(Function<Test[], Result> callback, String description, Test... tests) {
+ return new CompoundTest(callback, RUN_ALL, description, tests);
+ }
+
+ public static CompoundTest function(Function<Test[], Result> callback, Consumer<Test[]> runCallback, String description, Test... tests) {
+ return new CompoundTest(callback, runCallback, description, tests);
+ }
+
+ private static CompoundTest expectAll(Result.ExpectedValue what, Consumer<Test[]> runCallback, Test[] all) {
+ return new CompoundTest((tests) -> {
+ for (Test test : tests) {
+ if (!Result.Value.fromExpected(what, test.ok()).ok()) {
+ return new Result(Result.Value.FAILURE, "Some sub-tests did not have the expected result.");
+ }
+ }
+ return new Result(Result.Value.SUCCESS, "All sub-tests had the expected result.");
+ }, runCallback, all);
+ }
+
+ public static CompoundTest all(Result.ExpectedValue what, Test... all) {
+ return expectAll(what, RUN_ALL, all);
+ }
+
+ public static CompoundTest all(Result.ExpectedValue what, String description, Test... all) {
+ CompoundTest result = CompoundTest.all(what, all);
+ result.setDescription(description);
+ return result;
+ }
+
+ public static CompoundTest greedyAll(Result.ExpectedValue what, Test... all) {
+ return expectAll(what, RUN_GREEDY_ALL, all);
+ }
+
+ public static CompoundTest greedyAll(Result.ExpectedValue what, String description, Test... all) {
+ CompoundTest result = CompoundTest.greedyAll(what, all);
+ result.setDescription(description);
+ return result;
+ }
+
+ public static CompoundTest greedyAllTry(Result.ExpectedValue what, Test... all) {
+ return new CompoundTest((tests) -> {
+ int run = 0;
+ int ok = 0;
+ for (Test test : tests) {
+ if (test.hasRun()) {
+ run++;
+ if (Result.Value.fromExpected(what, test.ok()).ok()) {
+ ok++;
+ }
+ }
+ }
+ if (run == tests.length) {
+ if (ok == run) {
+ return new Result(Result.Value.SUCCESS, "All sub-tests had the expected result.");
+ } else {
+ return new Result(Result.Value.FAILURE, "Some sub-tests did not have the expected result.");
+ }
+ } else {
+ return new Result(Result.Value.SUCCESS, "All considered sub-tests had the expected result.");
+ }
+ }, RUN_GREEDY_ALL, all);
+ }
+
+ public static CompoundTest greedyAllTry(Result.ExpectedValue what, String description, Test... all) {
+ CompoundTest result = CompoundTest.greedyAllTry(what, all);
+ result.setDescription(description);
+ return result;
+ }
+
+ private static CompoundTest expectAny(Result.ExpectedValue what, Consumer<Test[]> runCallback, Test[] any) {
+ return new CompoundTest((tests) -> {
+ for (Test test : tests) {
+ if (Result.Value.fromExpected(what, test.ok()).ok()) {
+ return new Result(Result.Value.SUCCESS, "Some sub-tests did have the expected result.");
+ }
+ }
+ return new Result(Result.Value.FAILURE, "None of the sub-tests had the expected result.");
+ }, runCallback, any);
+ }
+
+ public static CompoundTest greedyAny(Result.ExpectedValue what, Test... any) {
+ return expectAny(what, RUN_GREEDY_ANY, any);
+ }
+
+ public static CompoundTest greedyAny(Result.ExpectedValue what, String description, Test... any) {
+ CompoundTest result = CompoundTest.greedyAny(what, any);
+ result.setDescription(description);
+ return result;
+ }
+
+ public static CompoundTest any(Result.ExpectedValue what, Test... any) {
+ return expectAny(what, RUN_ALL, any);
+ }
+
+ public static CompoundTest any(Result.ExpectedValue what, String description, Test... any) {
+ CompoundTest result = CompoundTest.any(what, any);
+ result.setDescription(description);
+ return result;
+ }
+
+ public static CompoundTest mask(Result.ExpectedValue[] results, Test... masked) {
+ return new CompoundTest((tests) -> {
+ for (int i = 0; i < results.length; ++i) {
+ if (!Result.Value.fromExpected(results[i], tests[i].ok()).ok()) {
+ return new Result(Result.Value.FAILURE, "Some sub-tests did not match the result mask.");
+ }
+ }
+ return new Result(Result.Value.SUCCESS, "All sub-tests matched the expected mask.");
+ }, RUN_ALL, masked);
+ }
+
+ public static CompoundTest mask(Result.ExpectedValue[] results, String description, Test... masked) {
+ CompoundTest result = CompoundTest.mask(results, masked);
+ result.setDescription(description);
+ return result;
+ }
+
+ public Test[] getTests() {
+ return tests.clone();
+ }
+
+ public Test[] getRunTests() {
+ return Arrays.stream(tests).filter(Test::hasRun).toArray(Test[]::new);
+ }
+
+ public Test[] getStartedTests() {
+ return Arrays.stream(tests).filter(Test::hasStarted).toArray(Test[]::new);
+ }
+
+ public Test[] getSkippedTests() {
+ return Arrays.stream(tests).filter((test) -> !test.hasRun()).toArray(Test[]::new);
+ }
+
+ @Override
+ protected void runSelf() {
+ runCallback.accept(tests);
+ result = resultCallback.apply(tests);
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public CompoundTest clone() throws CloneNotSupportedException {
+ return (CompoundTest) super.clone();
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/Result.java b/common/src/main/java/cz/crcs/ectester/common/test/Result.java
new file mode 100644
index 0000000..f065f9c
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/Result.java
@@ -0,0 +1,106 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * A Result of a Test. Has a Value and an optional String cause.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class Result {
+
+ private Value value;
+ private Object cause;
+
+ public Result(Value value) {
+ this.value = value;
+ }
+
+ public Result(Value value, Object cause) {
+ this(value);
+ this.cause = cause;
+ }
+
+ public Value getValue() {
+ return value;
+ }
+
+ public Object getCause() {
+ return cause;
+ }
+
+ public boolean ok() {
+ return value.ok();
+ }
+
+ public boolean compareTo(Result other) {
+ if (other == null) {
+ return false;
+ }
+ return value == other.value;
+ }
+
+ public boolean compareTo(Value other) {
+ if (other == null) {
+ return false;
+ }
+ return value == other;
+ }
+
+ /**
+ * A result value of a Test.
+ */
+ public enum Value {
+ SUCCESS(true, "Expected success."),
+ FAILURE(false, "Unexpected failure."),
+ UXSUCCESS(false, "Unexpected success."),
+ XFAILURE(true, "Expected failure."),
+ ERROR(false, "Error.");
+
+ private boolean ok;
+ private String desc;
+
+ Value(boolean ok) {
+ this.ok = ok;
+ }
+
+ Value(boolean ok, String desc) {
+ this(ok);
+ this.desc = desc;
+ }
+
+ public static Value fromExpected(ExpectedValue expected, boolean successful) {
+ switch (expected) {
+ case SUCCESS:
+ return successful ? SUCCESS : FAILURE;
+ case FAILURE:
+ return successful ? UXSUCCESS : XFAILURE;
+ case ANY:
+ return successful ? SUCCESS : XFAILURE;
+ }
+ return SUCCESS;
+ }
+
+ public static Value fromExpected(ExpectedValue expected, boolean successful, boolean error) {
+ if (error) {
+ return ERROR;
+ }
+ return fromExpected(expected, successful);
+ }
+
+ public boolean ok() {
+ return ok;
+ }
+
+ public String description() {
+ return desc;
+ }
+ }
+
+ /**
+ * A possible expected value result of a Test.
+ */
+ public enum ExpectedValue {
+ SUCCESS,
+ FAILURE,
+ ANY
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/SimpleTest.java b/common/src/main/java/cz/crcs/ectester/common/test/SimpleTest.java
new file mode 100644
index 0000000..d2b3e94
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/SimpleTest.java
@@ -0,0 +1,38 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * @param <T>
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class SimpleTest<T extends BaseTestable> extends Test implements Testable {
+ protected T testable;
+ protected TestCallback<T> callback;
+
+ public SimpleTest(T testable, TestCallback<T> callback) {
+ if (testable == null) {
+ throw new IllegalArgumentException("testable is null.");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("callback is null.");
+ }
+ this.testable = testable;
+ this.callback = callback;
+ }
+
+ public T getTestable() {
+ return testable;
+ }
+
+ @Override
+ protected void runSelf() {
+ testable.run();
+ result = callback.apply(testable);
+ }
+
+ @Override
+ public SimpleTest clone() throws CloneNotSupportedException {
+ SimpleTest clone = (SimpleTest) super.clone();
+ clone.testable = testable.clone();
+ return clone;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/Test.java b/common/src/main/java/cz/crcs/ectester/common/test/Test.java
new file mode 100644
index 0000000..8bf9502
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/Test.java
@@ -0,0 +1,83 @@
+package cz.crcs.ectester.common.test;
+
+import static cz.crcs.ectester.common.test.Result.Value;
+
+/**
+ * An abstract test that can be run and has a Result.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class Test implements Testable, Cloneable {
+ protected boolean hasRun;
+ protected boolean hasStarted;
+ protected Result result;
+
+ public Result getResult() {
+ return result;
+ }
+
+ public boolean ok() {
+ if (result == null) {
+ return true;
+ }
+ return result.ok();
+ }
+
+ @Override
+ public boolean error() {
+ if (result == null) {
+ return false;
+ }
+ return result.compareTo(Value.ERROR);
+ }
+
+ @Override
+ public Object errorCause() {
+ if (result == null || !result.compareTo(Value.ERROR)) {
+ return null;
+ }
+ return result.getCause();
+ }
+
+ @Override
+ public boolean hasRun() {
+ return hasRun;
+ }
+
+ public boolean hasStarted() {
+ return hasStarted;
+ }
+
+ @Override
+ public void reset() {
+ hasRun = false;
+ hasStarted = false;
+ result = null;
+ }
+
+ public abstract String getDescription();
+
+ @Override
+ public Test clone() throws CloneNotSupportedException {
+ return (Test) super.clone();
+ }
+
+ @Override
+ public void run() {
+ if (hasRun)
+ return;
+ try {
+ hasStarted = true;
+ runSelf();
+ hasRun = true;
+ } catch (TestException e) {
+ result = new Result(Value.ERROR, e);
+ throw e;
+ } catch (Exception e) {
+ result = new Result(Value.ERROR, e);
+ throw new TestException(e);
+ }
+ }
+
+ protected abstract void runSelf();
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/TestCallback.java b/common/src/main/java/cz/crcs/ectester/common/test/TestCallback.java
new file mode 100644
index 0000000..c5a49f3
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/TestCallback.java
@@ -0,0 +1,11 @@
+package cz.crcs.ectester.common.test;
+
+import java.util.function.Function;
+
+/**
+ * @param <T>
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class TestCallback<T extends Testable> implements Function<T, Result> {
+
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/TestException.java b/common/src/main/java/cz/crcs/ectester/common/test/TestException.java
new file mode 100644
index 0000000..0b605eb
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/TestException.java
@@ -0,0 +1,15 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * A TestException is an Exception that can be thrown during the running of a Testable,
+ * or a Test. It means that the Testable/TestSuite encountered an unexpected error
+ * and has to terminate.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public class TestException extends RuntimeException {
+ public TestException(Throwable e) {
+ super(e);
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/TestSuite.java b/common/src/main/java/cz/crcs/ectester/common/test/TestSuite.java
new file mode 100644
index 0000000..b12680a
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/TestSuite.java
@@ -0,0 +1,100 @@
+package cz.crcs.ectester.common.test;
+
+import cz.crcs.ectester.common.output.TestWriter;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class TestSuite {
+ protected String name;
+ protected String[] description;
+ private TestWriter writer;
+ private Test running;
+ private int ran = 0;
+ private int runFrom = 0;
+ private int runTo = -1;
+
+ public TestSuite(TestWriter writer, String name, String... description) {
+ this.writer = writer;
+ this.name = name;
+ this.description = description;
+ }
+
+ /**
+ * Run the <code>TestSuite</code>.
+ */
+ public void run() {
+ run(0);
+ }
+
+ public void run(int from) {
+ run(from, -1);
+ }
+
+ public void run(int from, int to) {
+ this.runFrom = from;
+ this.runTo = to;
+ writer.begin(this);
+ try {
+ runTests();
+ } catch (TestException e) {
+ writer.outputError(running, e, ran);
+ } catch (Exception e) {
+ writer.end();
+ throw new TestSuiteException(e);
+ }
+ writer.end();
+ }
+
+ /**
+ * Run the given test and return it back.
+ *
+ * @param t The test to run.
+ * @return The test that was run.
+ * @throws TestException
+ */
+ protected <T extends Test> T runTest(T t) {
+ running = t;
+ t.run();
+ running = null;
+ return t;
+ }
+
+ /**
+ * Run the given test, output it and return it back.
+ *
+ * @param t The test to run.
+ * @return The test that was run.
+ * @throws TestException
+ */
+ protected <T extends Test> T doTest(T t) {
+ if (ran >= runFrom && (runTo < 0 || ran <= runTo)) {
+ runTest(t);
+ writer.outputTest(t, ran);
+ }
+ ran++;
+ return t;
+ }
+
+ /**
+ *
+ */
+ protected abstract void runTests() throws Exception;
+
+ public String getName() {
+ return name;
+ }
+
+ public String[] getDescription() {
+ return description;
+ }
+
+ public String getTextDescription() {
+ return String.join(System.lineSeparator(), description);
+ }
+
+ public String toString() {
+ return null;
+ }
+
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/TestSuiteException.java b/common/src/main/java/cz/crcs/ectester/common/test/TestSuiteException.java
new file mode 100644
index 0000000..2d1ea09
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/TestSuiteException.java
@@ -0,0 +1,14 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * An unexpected exception was thrown while running a TestSuite, outside Test
+ * or a Testable.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public class TestSuiteException extends RuntimeException {
+ public TestSuiteException(Throwable e) {
+ super(e);
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/test/Testable.java b/common/src/main/java/cz/crcs/ectester/common/test/Testable.java
new file mode 100644
index 0000000..7b4545c
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/test/Testable.java
@@ -0,0 +1,38 @@
+package cz.crcs.ectester.common.test;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public interface Testable {
+ /**
+ * @return Whether this Testable was OK.
+ */
+ boolean ok();
+
+ /**
+ * @return Whether an error happened.
+ */
+ boolean error();
+
+ /**
+ * @return The cause of an error, if it happened, otherwise null.
+ */
+ Object errorCause();
+
+ /**
+ * @return Whether this runnable was run.
+ */
+ boolean hasRun();
+
+ /**
+ *
+ */
+ void reset();
+
+ /**
+ * Run this Runnable.
+ *
+ * @throws TestException If an unexpected exception/error is encountered.
+ */
+ void run();
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/util/ByteUtil.java b/common/src/main/java/cz/crcs/ectester/common/util/ByteUtil.java
new file mode 100644
index 0000000..442824a
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/util/ByteUtil.java
@@ -0,0 +1,193 @@
+package cz.crcs.ectester.common.util;
+
+/**
+ * Utility class, some byte/hex manipulation, convenient byte[] methods.
+ *
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ByteUtil {
+
+ /**
+ * Get a short from a byte array at <code>offset</code>, big-endian.
+ *
+ * @return the short value
+ */
+ public static short getShort(byte[] array, int offset) {
+ return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF));
+ }
+
+ /**
+ * Get a short from a byte array at <code>offset</code>, return it as an int, big-endian.
+ *
+ * @return the short value (as an int)
+ */
+ public static int getShortInt(byte[] array, int offset) {
+ return (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF));
+ }
+
+ /**
+ * Set a short in a byte array at <code>offset</code>, big-endian.
+ */
+ public static void setShort(byte[] array, int offset, short value) {
+ array[offset + 1] = (byte) (value & 0xFF);
+ array[offset] = (byte) ((value >> 8) & 0xFF);
+ }
+
+ /**
+ * Compare two byte arrays upto <code>length</code> and get first difference.
+ *
+ * @return the position of the first difference in the two byte arrays, or <code>length</code> if they are equal.
+ */
+ public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
+ for (int i = 0; i < length; ++i) {
+ byte a = one[i + oneOffset];
+ byte b = other[i + otherOffset];
+ if (a != b) {
+ return i;
+ }
+ }
+ return length;
+ }
+
+ /**
+ * Compare two byte arrays, upto <code>length</code>.
+ *
+ * @return whether the arrays are equal upto <code>length</code>
+ */
+ public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) {
+ return diffBytes(one, oneOffset, other, otherOffset, length) == length;
+ }
+
+ /**
+ * Test if the byte array has all values equal to <code>value</code>.
+ */
+ public static boolean allValue(byte[] array, byte value) {
+ for (byte a : array) {
+ if (a != value)
+ return false;
+ }
+ return true;
+ }
+
+ public static byte[] shortToBytes(short value) {
+ byte[] result = new byte[2];
+ setShort(result, 0, value);
+ return result;
+ }
+
+ public static byte[] shortToBytes(short[] shorts) {
+ if (shorts == null) {
+ return null;
+ }
+ byte[] result = new byte[shorts.length * 2];
+ for (int i = 0; i < shorts.length; ++i) {
+ setShort(result, 2 * i, shorts[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Parse a hex string into a byte array, big-endian.
+ *
+ * @param hex The String to parse.
+ * @return the byte array from the hex string.
+ */
+ public static byte[] hexToBytes(String hex) {
+ return hexToBytes(hex, true);
+ }
+
+ /**
+ * Parse a hex string into a byte-array, specify endianity.
+ *
+ * @param hex The String to parse.
+ * @param bigEndian Whether to parse as big-endian.
+ * @return the byte array from the hex string.
+ */
+ public static byte[] hexToBytes(String hex, boolean bigEndian) {
+ hex = hex.replace(" ", "");
+ int len = hex.length();
+ StringBuilder sb = new StringBuilder();
+
+ if (len % 2 == 1) {
+ sb.append("0");
+ ++len;
+ }
+
+ if (bigEndian) {
+ sb.append(hex);
+ } else {
+ for (int i = 0; i < len / 2; ++i) {
+ if (sb.length() >= 2) {
+ sb.insert(sb.length() - 2, hex.substring(2 * i, 2 * i + 2));
+ } else {
+ sb.append(hex.substring(2 * i, 2 * i + 2));
+ }
+
+ }
+ }
+
+ String data = sb.toString();
+ byte[] result = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ result[i / 2] = (byte) ((Character.digit(data.charAt(i), 16) << 4)
+ + (Character.digit(data.charAt(i + 1), 16)));
+ }
+ return result;
+ }
+
+ public static String byteToHex(byte data) {
+ return String.format("%02x", data);
+ }
+
+ public static String bytesToHex(byte[] data) {
+ return bytesToHex(data, true);
+ }
+
+ public static String bytesToHex(byte[] data, boolean addSpace) {
+ if (data == null) {
+ return "";
+ }
+ return bytesToHex(data, 0, data.length, addSpace);
+ }
+
+ public static String bytesToHex(byte[] data, int offset, int len) {
+ return bytesToHex(data, offset, len, true);
+ }
+
+ public static String bytesToHex(byte[] data, int offset, int len, boolean addSpace) {
+ if (data == null) {
+ return "";
+ }
+ StringBuilder buf = new StringBuilder();
+ for (int i = offset; i < (offset + len); i++) {
+ buf.append(byteToHex(data[i]));
+ if (addSpace && i != (offset + len - 1)) {
+ buf.append(" ");
+ }
+ }
+ return (buf.toString());
+ }
+
+ public static byte[] concatenate(byte[]... arrays) {
+ int len = 0;
+ for (byte[] array : arrays) {
+ if (array == null)
+ continue;
+ len += array.length;
+ }
+ byte[] out = new byte[len];
+ int offset = 0;
+ for (byte[] array : arrays) {
+ if (array == null || array.length == 0)
+ continue;
+ System.arraycopy(array, 0, out, offset, array.length);
+ offset += array.length;
+ }
+ return out;
+ }
+
+ public static byte[] prependLength(byte[] data) {
+ return concatenate(ByteUtil.shortToBytes((short) data.length), data);
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/util/CardConsts.java b/common/src/main/java/cz/crcs/ectester/common/util/CardConsts.java
new file mode 100644
index 0000000..1483346
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/util/CardConsts.java
@@ -0,0 +1,65 @@
+package cz.crcs.ectester.common.util;
+
+public class CardConsts {
+ // MAIN INSTRUCTION CLASS
+ public static final byte CLA_ECTESTERAPPLET = (byte) 0xB0;
+
+ // INSTRUCTIONS
+ public static final byte INS_ALLOCATE = (byte) 0x5a;
+ public static final byte INS_CLEAR = (byte) 0x5b;
+ public static final byte INS_SET = (byte) 0x5c;
+ public static final byte INS_TRANSFORM = (byte) 0x5d;
+ public static final byte INS_GENERATE = (byte) 0x5e;
+ public static final byte INS_EXPORT = (byte) 0x5f;
+ public static final byte INS_ECDH = (byte) 0x70;
+ public static final byte INS_ECDH_DIRECT = (byte) 0x71;
+ public static final byte INS_ECDSA = (byte) 0x72;
+ public static final byte INS_ECDSA_SIGN = (byte) 0x73;
+ public static final byte INS_ECDSA_VERIFY = (byte) 0x74;
+ public static final byte INS_CLEANUP = (byte) 0x75;
+ public static final byte INS_ALLOCATE_KA = (byte) 0x76;
+ public static final byte INS_ALLOCATE_SIG = (byte) 0x77;
+ public static final byte INS_GET_INFO = (byte) 0x78;
+ public static final byte INS_SET_DRY_RUN_MODE = (byte) 0x79;
+ public static final byte INS_BUFFER = (byte) 0x7a;
+ public static final byte INS_PERFORM = (byte) 0x7b;
+
+ // PARAMETERS for P1 and P2
+ public static final byte KEYPAIR_LOCAL = (byte) 0x01;
+ public static final byte KEYPAIR_REMOTE = (byte) 0x02;
+ public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE;
+ public static final byte BUILD_KEYPAIR = (byte) 0x01;
+ public static final byte BUILD_KEYBUILDER = (byte) 0x02;
+ public static final byte EXPORT_TRUE = (byte) 0xff;
+ public static final byte EXPORT_FALSE = (byte) 0x00;
+ public static final byte MODE_NORMAL = (byte) 0xaa;
+ public static final byte MODE_DRY_RUN = (byte) 0xbb;
+
+ // STATUS WORDS
+ public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1;
+ public static final short SW_DH_DHC_MISMATCH = (short) 0x0ee2;
+ public static final short SW_KEYPAIR_NULL = (short) 0x0ee3;
+ public static final short SW_KA_NULL = (short) 0x0ee4;
+ public static final short SW_SIGNATURE_NULL = (short) 0x0ee5;
+ public static final short SW_OBJECT_NULL = (short) 0x0ee6;
+ public static final short SW_CANNOT_FIT = (short) 0x0ee7;
+ public static final short SW_Exception = (short) 0xff01;
+ public static final short SW_ArrayIndexOutOfBoundsException = (short) 0xff02;
+ public static final short SW_ArithmeticException = (short) 0xff03;
+ public static final short SW_ArrayStoreException = (short) 0xff04;
+ public static final short SW_NullPointerException = (short) 0xff05;
+ public static final short SW_NegativeArraySizeException = (short) 0xff06;
+ public static final short SW_CryptoException_prefix = (short) 0xf100;
+ public static final short SW_SystemException_prefix = (short) 0xf200;
+ public static final short SW_PINException_prefix = (short) 0xf300;
+ public static final short SW_TransactionException_prefix = (short) 0xf400;
+ public static final short SW_CardRuntimeException_prefix = (short) 0xf500;
+
+ //
+ public static final short BASE_221 = (short) 0x0221;
+ public static final short BASE_222 = (short) 0x0222;
+
+ //
+ public static final short CDATA_BASIC = (short) 5;
+ public static final short CDATA_EXTENDED = (short) 7;
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/util/CardUtil.java b/common/src/main/java/cz/crcs/ectester/common/util/CardUtil.java
new file mode 100644
index 0000000..eeb2159
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/util/CardUtil.java
@@ -0,0 +1,569 @@
+package cz.crcs.ectester.common.util;
+
+import cz.crcs.ectester.common.ec.EC_Consts;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CardUtil {
+ public class ISO7816 {
+ public static final short SW_APPLET_SELECT_FAILED = 27033;
+ public static final short SW_BYTES_REMAINING_00 = 24832;
+ public static final short SW_CLA_NOT_SUPPORTED = 28160;
+ public static final short SW_COMMAND_CHAINING_NOT_SUPPORTED = 26756;
+ public static final short SW_COMMAND_NOT_ALLOWED = 27014;
+ public static final short SW_CONDITIONS_NOT_SATISFIED = 27013;
+ public static final short SW_CORRECT_LENGTH_00 = 27648;
+ public static final short SW_DATA_INVALID = 27012;
+ public static final short SW_FILE_FULL = 27268;
+ public static final short SW_FILE_INVALID = 27011;
+ public static final short SW_FILE_NOT_FOUND = 27266;
+ public static final short SW_FUNC_NOT_SUPPORTED = 27265;
+ public static final short SW_INCORRECT_P1P2 = 27270;
+ public static final short SW_INS_NOT_SUPPORTED = 27904;
+ public static final short SW_LAST_COMMAND_EXPECTED = 26755;
+ public static final short SW_LOGICAL_CHANNEL_NOT_SUPPORTED = 26753;
+ public static final short SW_NO_ERROR = -28672;
+ public static final short SW_RECORD_NOT_FOUND = 27267;
+ public static final short SW_SECURE_MESSAGING_NOT_SUPPORTED = 26754;
+ public static final short SW_SECURITY_STATUS_NOT_SATISFIED = 27010;
+ public static final short SW_UNKNOWN = 28416;
+ public static final short SW_WARNING_STATE_UNCHANGED = 25088;
+ public static final short SW_WRONG_DATA = 27264;
+ public static final short SW_WRONG_LENGTH = 26368;
+ public static final short SW_WRONG_P1P2 = 27392;
+ }
+
+ public class CryptoException {
+ public static final short ILLEGAL_VALUE = 1;
+ public static final short UNINITIALIZED_KEY = 2;
+ public static final short NO_SUCH_ALGORITHM = 3;
+ public static final short INVALID_INIT = 4;
+ public static final short ILLEGAL_USE = 5;
+ }
+
+ public static byte getSig(String name) {
+ switch (name) {
+ case "SHA1":
+ return EC_Consts.Signature_ALG_ECDSA_SHA;
+ case "SHA224":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_224;
+ case "SHA256":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_256;
+ case "SHA384":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_384;
+ case "SHA512":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_512;
+ default:
+ return EC_Consts.Signature_ALG_ECDSA_SHA;
+ }
+ }
+
+ public static String getSigHashAlgo(byte sigType) {
+ switch (sigType) {
+ case EC_Consts.Signature_ALG_ECDSA_SHA:
+ return "SHA1";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_224:
+ return "SHA224";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_256:
+ return "SHA256";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_384:
+ return "SHA384";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_512:
+ return "SHA512";
+ default:
+ return null;
+ }
+ }
+
+ public static String getSigHashName(byte sigType) {
+ switch (sigType) {
+ case EC_Consts.Signature_ALG_ECDSA_SHA:
+ return "SHA1";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_224:
+ return "SHA224";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_256:
+ return "SHA256";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_384:
+ return "SHA384";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_512:
+ return "SHA512";
+ default:
+ return null;
+ }
+ }
+
+ public static byte getKA(String name) {
+ switch (name) {
+ case "DH":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH;
+ case "DHC":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC;
+ case "DH_PLAIN":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN;
+ case "DHC_PLAIN":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN;
+ case "PACE_GM":
+ return EC_Consts.KeyAgreement_ALG_EC_PACE_GM;
+ case "DH_PLAIN_XY":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY;
+ default:
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH;
+ }
+ }
+
+ public static String getKexHashName(byte kexType) {
+ switch (kexType) {
+ case EC_Consts.KeyAgreement_ALG_EC_SVDP_DH:
+ case EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC:
+ return "SHA1";
+ default:
+ return "NONE";
+ }
+ }
+
+ public static String getSWSource(short sw) {
+ switch (sw) {
+ case ISO7816.SW_NO_ERROR:
+ case ISO7816.SW_APPLET_SELECT_FAILED:
+ case ISO7816.SW_BYTES_REMAINING_00:
+ case ISO7816.SW_CLA_NOT_SUPPORTED:
+ case ISO7816.SW_COMMAND_NOT_ALLOWED:
+ case ISO7816.SW_COMMAND_CHAINING_NOT_SUPPORTED:
+ case ISO7816.SW_CONDITIONS_NOT_SATISFIED:
+ case ISO7816.SW_CORRECT_LENGTH_00:
+ case ISO7816.SW_DATA_INVALID:
+ case ISO7816.SW_FILE_FULL:
+ case ISO7816.SW_FILE_INVALID:
+ case ISO7816.SW_FILE_NOT_FOUND:
+ case ISO7816.SW_FUNC_NOT_SUPPORTED:
+ case ISO7816.SW_INCORRECT_P1P2:
+ case ISO7816.SW_INS_NOT_SUPPORTED:
+ case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED:
+ case ISO7816.SW_RECORD_NOT_FOUND:
+ case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED:
+ case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED:
+ case ISO7816.SW_UNKNOWN:
+ case ISO7816.SW_WARNING_STATE_UNCHANGED:
+ case ISO7816.SW_WRONG_DATA:
+ case ISO7816.SW_WRONG_LENGTH:
+ case ISO7816.SW_WRONG_P1P2:
+ return "ISO";
+ case CryptoException.ILLEGAL_VALUE:
+ case CryptoException.UNINITIALIZED_KEY:
+ case CryptoException.NO_SUCH_ALGORITHM:
+ case CryptoException.INVALID_INIT:
+ case CryptoException.ILLEGAL_USE:
+ return "CryptoException";
+ case CardConsts.SW_SIG_VERIFY_FAIL:
+ case CardConsts.SW_DH_DHC_MISMATCH:
+ case CardConsts.SW_KEYPAIR_NULL:
+ case CardConsts.SW_KA_NULL:
+ case CardConsts.SW_SIGNATURE_NULL:
+ case CardConsts.SW_OBJECT_NULL:
+ return "ECTesterApplet";
+ default:
+ return "?";
+ }
+ }
+
+ public static String getSW(short sw) {
+ int upper = (sw & 0xff00) >> 8;
+ int lower = (sw & 0xff);
+ switch (upper) {
+ case 0xf1:
+ return String.format("CryptoException(%d)", lower);
+ case 0xf2:
+ return String.format("SystemException(%d)", lower);
+ case 0xf3:
+ return String.format("PINException(%d)", lower);
+ case 0xf4:
+ return String.format("TransactionException(%d)", lower);
+ case 0xf5:
+ return String.format("CardRuntimeException(%d)", lower);
+ default:
+ switch (sw) {
+ case ISO7816.SW_APPLET_SELECT_FAILED:
+ return "APPLET_SELECT_FAILED";
+ case ISO7816.SW_BYTES_REMAINING_00:
+ return "BYTES_REMAINING";
+ case ISO7816.SW_CLA_NOT_SUPPORTED:
+ return "CLA_NOT_SUPPORTED";
+ case ISO7816.SW_COMMAND_NOT_ALLOWED:
+ return "COMMAND_NOT_ALLOWED";
+ case ISO7816.SW_COMMAND_CHAINING_NOT_SUPPORTED:
+ return "COMMAND_CHAINING_NOT_SUPPORTED";
+ case ISO7816.SW_CONDITIONS_NOT_SATISFIED:
+ return "CONDITIONS_NOT_SATISFIED";
+ case ISO7816.SW_CORRECT_LENGTH_00:
+ return "CORRECT_LENGTH";
+ case ISO7816.SW_DATA_INVALID:
+ return "DATA_INVALID";
+ case ISO7816.SW_FILE_FULL:
+ return "FILE_FULL";
+ case ISO7816.SW_FILE_INVALID:
+ return "FILE_INVALID";
+ case ISO7816.SW_FILE_NOT_FOUND:
+ return "FILE_NOT_FOUND";
+ case ISO7816.SW_FUNC_NOT_SUPPORTED:
+ return "FUNC_NOT_SUPPORTED";
+ case ISO7816.SW_INCORRECT_P1P2:
+ return "INCORRECT_P1P2";
+ case ISO7816.SW_INS_NOT_SUPPORTED:
+ return "INS_NOT_SUPPORTED";
+ case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED:
+ return "LOGICAL_CHANNEL_NOT_SUPPORTED";
+ case ISO7816.SW_RECORD_NOT_FOUND:
+ return "RECORD_NOT_FOUND";
+ case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED:
+ return "SECURE_MESSAGING_NOT_SUPPORTED";
+ case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED:
+ return "SECURITY_STATUS_NOT_SATISFIED";
+ case ISO7816.SW_UNKNOWN:
+ return "UNKNOWN";
+ case ISO7816.SW_WARNING_STATE_UNCHANGED:
+ return "WARNING_STATE_UNCHANGED";
+ case ISO7816.SW_WRONG_DATA:
+ return "WRONG_DATA";
+ case ISO7816.SW_WRONG_LENGTH:
+ return "WRONG_LENGTH";
+ case ISO7816.SW_WRONG_P1P2:
+ return "WRONG_P1P2";
+ case CryptoException.ILLEGAL_VALUE:
+ return "ILLEGAL_VALUE";
+ case CryptoException.UNINITIALIZED_KEY:
+ return "UNINITIALIZED_KEY";
+ case CryptoException.NO_SUCH_ALGORITHM:
+ return "NO_SUCH_ALG";
+ case CryptoException.INVALID_INIT:
+ return "INVALID_INIT";
+ case CryptoException.ILLEGAL_USE:
+ return "ILLEGAL_USE";
+ case CardConsts.SW_SIG_VERIFY_FAIL:
+ return "SIG_VERIFY_FAIL";
+ case CardConsts.SW_DH_DHC_MISMATCH:
+ return "DH_DHC_MISMATCH";
+ case CardConsts.SW_KEYPAIR_NULL:
+ return "KEYPAIR_NULL";
+ case CardConsts.SW_KA_NULL:
+ return "KA_NULL";
+ case CardConsts.SW_SIGNATURE_NULL:
+ return "SIGNATURE_NULL";
+ case CardConsts.SW_OBJECT_NULL:
+ return "OBJECT_NULL";
+ case CardConsts.SW_Exception:
+ return "Exception";
+ case CardConsts.SW_ArrayIndexOutOfBoundsException:
+ return "ArrayIndexOutOfBoundsException";
+ case CardConsts.SW_ArithmeticException:
+ return "ArithmeticException";
+ case CardConsts.SW_ArrayStoreException:
+ return "ArrayStoreException";
+ case CardConsts.SW_NullPointerException:
+ return "NullPointerException";
+ case CardConsts.SW_NegativeArraySizeException:
+ return "NegativeArraySizeException";
+ default:
+ return "unknown";
+ }
+ }
+ }
+
+ public static String getSWString(short sw) {
+ if (sw == ISO7816.SW_NO_ERROR) {
+ return "OK (0x9000)";
+ } else {
+ String str = getSW(sw);
+ return String.format("fail (%s, 0x%04x)", str, sw);
+ }
+ }
+
+ public static String getParams(short params) {
+ if (params == 0) {
+ return "";
+ }
+ List<String> ps = new LinkedList<>();
+ short paramMask = EC_Consts.PARAMETER_FP;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ short paramValue = (short) (paramMask & params);
+ if (paramValue != 0) {
+ switch (paramValue) {
+ case EC_Consts.PARAMETER_FP:
+ ps.add("P");
+ break;
+ case EC_Consts.PARAMETER_F2M:
+ ps.add("2^M");
+ break;
+ case EC_Consts.PARAMETER_A:
+ ps.add("A");
+ break;
+ case EC_Consts.PARAMETER_B:
+ ps.add("B");
+ break;
+ case EC_Consts.PARAMETER_G:
+ ps.add("G");
+ break;
+ case EC_Consts.PARAMETER_R:
+ ps.add("R");
+ break;
+ case EC_Consts.PARAMETER_K:
+ ps.add("K");
+ break;
+ case EC_Consts.PARAMETER_W:
+ ps.add("W");
+ break;
+ case EC_Consts.PARAMETER_S:
+ ps.add("S");
+ break;
+ }
+ }
+ paramMask = (short) (paramMask << 1);
+ }
+
+ if (ps.size() != 0) {
+ return "[" + String.join(",", ps) + "]";
+ } else {
+ return "unknown";
+ }
+ }
+
+ public static String getTransformation(short transformationType) {
+ if (transformationType == 0) {
+ return "NONE";
+ }
+ List<String> names = new LinkedList<>();
+ short transformationMask = 1;
+ while (transformationMask <= EC_Consts.TRANSFORMATION_04_MASK) {
+ short transformationValue = (short) (transformationMask & transformationType);
+ if (transformationValue != 0) {
+ switch (transformationValue) {
+ case EC_Consts.TRANSFORMATION_FIXED:
+ names.add("FIXED");
+ break;
+ case EC_Consts.TRANSFORMATION_ONE:
+ names.add("ONE");
+ break;
+ case EC_Consts.TRANSFORMATION_ZERO:
+ names.add("ZERO");
+ break;
+ case EC_Consts.TRANSFORMATION_ONEBYTERANDOM:
+ names.add("ONE_BYTE_RANDOM");
+ break;
+ case EC_Consts.TRANSFORMATION_FULLRANDOM:
+ names.add("FULL_RANDOM");
+ break;
+ case EC_Consts.TRANSFORMATION_INCREMENT:
+ names.add("INCREMENT");
+ break;
+ case EC_Consts.TRANSFORMATION_INFINITY:
+ names.add("INFINITY");
+ break;
+ case EC_Consts.TRANSFORMATION_COMPRESS:
+ names.add("COMPRESSED");
+ break;
+ case EC_Consts.TRANSFORMATION_COMPRESS_HYBRID:
+ names.add("HYBRID");
+ break;
+ case EC_Consts.TRANSFORMATION_04_MASK:
+ names.add("MASK(O4)");
+ break;
+ case EC_Consts.TRANSFORMATION_MAX:
+ names.add("MAX");
+ break;
+ }
+ }
+ transformationMask = (short) ((transformationMask) << 1);
+ }
+ if (names.size() != 0) {
+ return String.join(" + ", names);
+ } else {
+ return "unknown";
+ }
+ }
+
+ public static String getKATypeString(byte kaType) {
+ switch (kaType) {
+ case EC_Consts.KeyAgreement_ALG_EC_SVDP_DH:
+ return "ALG_EC_SVDP_DH";
+ case EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN:
+ return "ALG_EC_SVDP_DH_PLAIN";
+ case EC_Consts.KeyAgreement_ALG_EC_PACE_GM:
+ return "ALG_EC_PACE_GM";
+ case EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY:
+ return "ALG_EC_SVDP_DH_PLAIN_XY";
+ case EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC:
+ return "ALG_EC_SVDP_DHC";
+ case EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN:
+ return "ALG_EC_SVDP_DHC_PLAIN";
+ default:
+ return "unknown";
+ }
+ }
+
+ public static byte getKAType(String kaTypeString) {
+ switch (kaTypeString) {
+ case "DH":
+ case "ALG_EC_SVDP_DH":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH;
+ case "DH_PLAIN":
+ case "ALG_EC_SVDP_DH_PLAIN":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN;
+ case "PACE_GM":
+ case "ALG_EC_PACE_GM":
+ return EC_Consts.KeyAgreement_ALG_EC_PACE_GM;
+ case "DH_PLAIN_XY":
+ case "ALG_EC_SVDP_DH_PLAIN_XY":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY;
+ case "DHC":
+ case "ALG_EC_SVDP_DHC":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC;
+ case "DHC_PLAIN":
+ case "ALG_EC_SVDP_DHC_PLAIN":
+ return EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN;
+ default:
+ return 0;
+ }
+ }
+
+ public static byte parseKAType(String kaTypeString) {
+ byte kaType;
+ try {
+ kaType = Byte.parseByte(kaTypeString);
+ } catch (NumberFormatException nfex) {
+ kaType = getKAType(kaTypeString);
+ }
+ return kaType;
+ }
+
+ public static String getSigTypeString(byte sigType) {
+ switch (sigType) {
+ case EC_Consts.Signature_ALG_ECDSA_SHA:
+ return "ALG_ECDSA_SHA";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_224:
+ return "ALG_ECDSA_SHA_224";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_256:
+ return "ALG_ECDSA_SHA_256";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_384:
+ return "ALG_ECDSA_SHA_384";
+ case EC_Consts.Signature_ALG_ECDSA_SHA_512:
+ return "ALG_ECDSA_SHA_512";
+ default:
+ return "unknown";
+ }
+ }
+
+ public static byte getSigType(String sigTypeString) {
+ switch (sigTypeString) {
+ case "ECDSA_SHA":
+ case "ALG_ECDSA_SHA":
+ return EC_Consts.Signature_ALG_ECDSA_SHA;
+ case "ECDSA_SHA_224":
+ case "ALG_ECDSA_SHA_224":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_224;
+ case "ECDSA_SHA_256":
+ case "ALG_ECDSA_SHA_256":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_256;
+ case "ECDSA_SHA_384":
+ case "ALG_ECDSA_SHA_384":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_384;
+ case "ECDSA_SHA_512":
+ case "ALG_ECDSA_SHA_512":
+ return EC_Consts.Signature_ALG_ECDSA_SHA_512;
+ default:
+ return 0;
+ }
+ }
+
+ public static byte parseSigType(String sigTypeString) {
+ byte sigType;
+ try {
+ sigType = Byte.parseByte(sigTypeString);
+ } catch (NumberFormatException nfex) {
+ sigType = getSigType(sigTypeString);
+ }
+ return sigType;
+ }
+
+ public static String getKeyTypeString(byte keyClass) {
+ switch (keyClass) {
+ case EC_Consts.ALG_EC_FP:
+ return "ALG_EC_FP";
+ case EC_Consts.ALG_EC_F2M:
+ return "ALG_EC_F2M";
+ default:
+ return "";
+ }
+ }
+
+ public static String getCurveName(byte curve) {
+ String result = "";
+ switch (curve) {
+ case EC_Consts.CURVE_default:
+ result = "default";
+ break;
+ case EC_Consts.CURVE_external:
+ result = "external";
+ break;
+ case EC_Consts.CURVE_secp112r1:
+ result = "secp112r1";
+ break;
+ case EC_Consts.CURVE_secp128r1:
+ result = "secp128r1";
+ break;
+ case EC_Consts.CURVE_secp160r1:
+ result = "secp160r1";
+ break;
+ case EC_Consts.CURVE_secp192r1:
+ result = "secp192r1";
+ break;
+ case EC_Consts.CURVE_secp224r1:
+ result = "secp224r1";
+ break;
+ case EC_Consts.CURVE_secp256r1:
+ result = "secp256r1";
+ break;
+ case EC_Consts.CURVE_secp384r1:
+ result = "secp384r1";
+ break;
+ case EC_Consts.CURVE_secp521r1:
+ result = "secp521r1";
+ break;
+ case EC_Consts.CURVE_sect163r1:
+ result = "sect163r1";
+ break;
+ case EC_Consts.CURVE_sect233r1:
+ result = "sect233r1";
+ break;
+ case EC_Consts.CURVE_sect283r1:
+ result = "sect283r1";
+ break;
+ case EC_Consts.CURVE_sect409r1:
+ result = "sect409r1";
+ break;
+ case EC_Consts.CURVE_sect571r1:
+ result = "sect571r1";
+ break;
+ }
+ return result;
+ }
+
+ public static String getParameterString(short params) {
+ String what = "";
+ if (params == EC_Consts.PARAMETERS_DOMAIN_F2M || params == EC_Consts.PARAMETERS_DOMAIN_FP) {
+ what = "curve";
+ } else if (params == EC_Consts.PARAMETER_W) {
+ what = "pubkey";
+ } else if (params == EC_Consts.PARAMETER_S) {
+ what = "privkey";
+ } else if (params == EC_Consts.PARAMETERS_KEYPAIR) {
+ what = "keypair";
+ } else {
+ what = getParams(params);
+ }
+ return what;
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/util/ECUtil.java b/common/src/main/java/cz/crcs/ectester/common/util/ECUtil.java
new file mode 100644
index 0000000..773644b
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/util/ECUtil.java
@@ -0,0 +1,467 @@
+package cz.crcs.ectester.common.util;
+
+import cz.crcs.ectester.common.ec.*;
+import cz.crcs.ectester.data.EC_Store;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.signers.PlainDSAEncoding;
+import org.bouncycastle.crypto.signers.StandardDSAEncoding;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.*;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ECUtil {
+ private static Random rand = new Random();
+
+ public static byte[] toByteArray(BigInteger what, int bits) {
+ byte[] raw = what.toByteArray();
+ int bytes = (bits + 7) / 8;
+ if (raw.length < bytes) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw, 0, result, bytes - raw.length, raw.length);
+ return result;
+ }
+ if (bytes < raw.length) {
+ byte[] result = new byte[bytes];
+ System.arraycopy(raw, raw.length - bytes, result, 0, bytes);
+ return result;
+ }
+ return raw;
+ }
+
+ public static byte[] toX962Compressed(byte[][] point) {
+ if (point.length != 2) {
+ return null;
+ }
+ byte ybit = (byte) (point[1][point[1].length - 1] % 2);
+ return ByteUtil.concatenate(new byte[]{(byte) (0x02 | ybit)}, point[0]);
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte marker = (byte) (0x02 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x);
+ }
+
+ public static byte[] toX962Compressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Compressed(point, spec.getOrder().bitLength());
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
+ return ByteUtil.concatenate(new byte[]{0x04}, x, y);
+ }
+
+ public static byte[] toX962Uncompressed(ECPoint point, ECParameterSpec spec) {
+ return toX962Uncompressed(point, spec.getOrder().bitLength());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, int bits) {
+ if (point.equals(ECPoint.POINT_INFINITY)) {
+ return new byte[]{0};
+ }
+ byte[] x = toByteArray(point.getAffineX(), bits);
+ byte[] y = toByteArray(point.getAffineY(), bits);
+ byte marker = (byte) (0x06 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue());
+ return ByteUtil.concatenate(new byte[]{marker}, x, y);
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, EllipticCurve curve) {
+ return toX962Hybrid(point, curve.getField().getFieldSize());
+ }
+
+ public static byte[] toX962Hybrid(ECPoint point, ECParameterSpec spec) {
+ return toX962Hybrid(point, spec.getCurve());
+ }
+
+ private static boolean isResidue(BigInteger a, BigInteger p) {
+ BigInteger exponent = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger result = a.modPow(exponent, p);
+ return result.equals(BigInteger.ONE);
+ }
+
+ private static BigInteger modSqrt(BigInteger a, BigInteger p) {
+ BigInteger q = p.subtract(BigInteger.ONE);
+ int s = 0;
+ while (q.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
+ q = q.divide(BigInteger.valueOf(2));
+ s++;
+ }
+
+ BigInteger z = BigInteger.ONE;
+ do {
+ z = z.add(BigInteger.ONE);
+ } while (isResidue(z, p));
+
+ BigInteger m = BigInteger.valueOf(s);
+ BigInteger c = z.modPow(q, p);
+ BigInteger t = a.modPow(q, p);
+ BigInteger rExponent = q.add(BigInteger.ONE).divide(BigInteger.valueOf(2));
+ BigInteger r = a.modPow(rExponent, p);
+
+ while (!t.equals(BigInteger.ONE)) {
+ int i = 0;
+ BigInteger exponent;
+ do {
+ exponent = BigInteger.valueOf(2).pow(++i);
+ } while (!t.modPow(exponent, p).equals(BigInteger.ONE));
+
+ BigInteger twoExponent = m.subtract(BigInteger.valueOf(i + 1));
+ BigInteger b = c.modPow(BigInteger.valueOf(2).modPow(twoExponent, p), p);
+ m = BigInteger.valueOf(i);
+ c = b.modPow(BigInteger.valueOf(2), p);
+ t = t.multiply(c).mod(p);
+ r = r.multiply(b).mod(p);
+ }
+ return r;
+ }
+
+ public static ECPoint fromX962(byte[] data, EllipticCurve curve) {
+ if (data == null) {
+ return null;
+ }
+ if (data[0] == 0x04 || data[0] == 0x06 || data[0] == 0x07) {
+ int len = (data.length - 1) / 2;
+ byte[] xbytes = new byte[len];
+ System.arraycopy(data, 1, xbytes, 0, len);
+ byte[] ybytes = new byte[len];
+ System.arraycopy(data, 1 + len, ybytes, 0, len);
+ return new ECPoint(new BigInteger(1, xbytes), new BigInteger(1, ybytes));
+ } else if (data[0] == 0x02 || data[0] == 0x03) {
+ if (curve == null) {
+ throw new IllegalArgumentException();
+ }
+ byte[] xbytes = new byte[data.length - 1];
+ System.arraycopy(data, 1, xbytes, 0, data.length - 1);
+ BigInteger x = new BigInteger(1, xbytes);
+ BigInteger a = curve.getA();
+ BigInteger b = curve.getB();
+
+ ECField field = curve.getField();
+ if (field instanceof ECFieldFp) {
+ BigInteger p = ((ECFieldFp) field).getP();
+ BigInteger alpha = x.modPow(BigInteger.valueOf(3), p);
+ alpha = alpha.add(x.multiply(a));
+ alpha = alpha.add(b);
+
+ if (!isResidue(alpha, p)) {
+ throw new IllegalArgumentException();
+ }
+
+ BigInteger beta = modSqrt(alpha, p);
+ if (beta.getLowestSetBit() == 0) {
+ // rightmost bit is one
+ if (data[0] == 0x02) {
+ // yp is 0
+ beta = p.subtract(beta);
+ }
+ } else {
+ // rightmost bit is zero
+ if (data[0] == 0x03) {
+ // yp is 1
+ beta = p.subtract(beta);
+ }
+ }
+
+ return new ECPoint(x, beta);
+ } else if (field instanceof ECFieldF2m) {
+ //TODO
+ throw new UnsupportedOperationException();
+ }
+ return null;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ private static byte[] hashCurve(EC_Curve curve) {
+ int bytes = (curve.getBits() + 7) / 8;
+ byte[] result = new byte[bytes];
+ SHA1Digest digest = new SHA1Digest();
+ byte[] curveName = curve.getId().getBytes(StandardCharsets.US_ASCII);
+ digest.update(curveName, 0, curveName.length);
+ int written = 0;
+ while (written < bytes) {
+ byte[] dig = new byte[digest.getDigestSize()];
+ digest.doFinal(dig, 0);
+ int toWrite = Math.min(digest.getDigestSize(), bytes - written);
+ System.arraycopy(dig, 0, result, written, toWrite);
+ written += toWrite;
+ digest.update(dig, 0, dig.length);
+ }
+ return result;
+ }
+
+ public static EC_Params fullRandomKey(EC_Curve curve) {
+ int bytes = (curve.getBits() + 7) / 8;
+ byte[] result = new byte[bytes];
+ rand.nextBytes(result);
+ BigInteger priv = new BigInteger(1, result);
+ BigInteger order = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_R)[0]);
+ priv = priv.mod(order);
+ return new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{toByteArray(priv, curve.getBits())});
+ }
+
+ public static EC_Params fixedRandomKey(EC_Curve curve) {
+ byte[] hash = hashCurve(curve);
+ BigInteger priv = new BigInteger(1, hash);
+ BigInteger order = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_R)[0]);
+ priv = priv.mod(order);
+ return new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{toByteArray(priv, curve.getBits())});
+ }
+
+ private static BigInteger computeRHS(BigInteger x, BigInteger a, BigInteger b, BigInteger p) {
+ BigInteger rhs = x.modPow(BigInteger.valueOf(3), p);
+ rhs = rhs.add(a.multiply(x)).mod(p);
+ rhs = rhs.add(b).mod(p);
+ return rhs;
+ }
+
+ public static EC_Params fullRandomPoint(EC_Curve curve) {
+ EllipticCurve ecCurve = curve.toCurve();
+
+ BigInteger p;
+ if (ecCurve.getField() instanceof ECFieldFp) {
+ ECFieldFp fp = (ECFieldFp) ecCurve.getField();
+ p = fp.getP();
+ if (!p.isProbablePrime(20)) {
+ return null;
+ }
+ } else {
+ //TODO
+ return null;
+ }
+ BigInteger x;
+ BigInteger rhs;
+ do {
+ x = new BigInteger(ecCurve.getField().getFieldSize(), rand).mod(p);
+ rhs = computeRHS(x, ecCurve.getA(), ecCurve.getB(), p);
+ } while (!isResidue(rhs, p));
+ BigInteger y = modSqrt(rhs, p);
+ if (rand.nextBoolean()) {
+ y = p.subtract(y);
+ }
+
+ byte[] xArr = toByteArray(x, ecCurve.getField().getFieldSize());
+ byte[] yArr = toByteArray(y, ecCurve.getField().getFieldSize());
+ return new EC_Params(EC_Consts.PARAMETER_W, new byte[][]{xArr, yArr});
+ }
+
+ public static EC_Params fixedRandomPoint(EC_Curve curve) {
+ EllipticCurve ecCurve = curve.toCurve();
+
+ BigInteger p;
+ if (ecCurve.getField() instanceof ECFieldFp) {
+ ECFieldFp fp = (ECFieldFp) ecCurve.getField();
+ p = fp.getP();
+ if (!p.isProbablePrime(20)) {
+ return null;
+ }
+ } else {
+ //TODO
+ return null;
+ }
+
+ BigInteger x = new BigInteger(1, hashCurve(curve)).mod(p);
+ BigInteger rhs = computeRHS(x, ecCurve.getA(), ecCurve.getB(), p);
+ while (!isResidue(rhs, p)) {
+ x = x.add(BigInteger.ONE).mod(p);
+ rhs = computeRHS(x, ecCurve.getA(), ecCurve.getB(), p);
+ }
+ BigInteger y = modSqrt(rhs, p);
+ if (y.bitCount() % 2 == 0) {
+ y = p.subtract(y);
+ }
+
+ byte[] xArr = toByteArray(x, ecCurve.getField().getFieldSize());
+ byte[] yArr = toByteArray(y, ecCurve.getField().getFieldSize());
+ return new EC_Params(EC_Consts.PARAMETER_W, new byte[][]{xArr, yArr});
+ }
+
+ public static ECPoint toPoint(EC_Params params) {
+ return new ECPoint(
+ new BigInteger(1, params.getParam(EC_Consts.PARAMETER_W)[0]),
+ new BigInteger(1, params.getParam(EC_Consts.PARAMETER_W)[1]));
+ }
+
+ public static BigInteger toScalar(EC_Params params) {
+ return new BigInteger(1, params.getParam(EC_Consts.PARAMETER_S)[0]);
+ }
+
+ public static ECPublicKey toPublicKey(EC_Key.Public pubkey) {
+ if (pubkey == null) {
+ return null;
+ }
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, pubkey.getCurve());
+ if (curve == null) {
+ throw new IllegalArgumentException("pubkey curve not found: " + pubkey.getCurve());
+ }
+ return new RawECPublicKey(toPoint(pubkey), curve.toSpec());
+ }
+
+ public static ECPrivateKey toPrivateKey(EC_Key.Private privkey) {
+ if (privkey == null) {
+ return null;
+ }
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, privkey.getCurve());
+ if (curve == null) {
+ throw new IllegalArgumentException("privkey curve not found: " + privkey.getCurve());
+ }
+ return new RawECPrivateKey(toScalar(privkey), curve.toSpec());
+ }
+
+ public static KeyPair toKeyPair(EC_Keypair kp) {
+ if (kp == null) {
+ return null;
+ }
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, kp.getCurve());
+ if (curve == null) {
+ throw new IllegalArgumentException("keypair curve not found: " + kp.getCurve());
+ }
+ ECPublicKey pubkey = new RawECPublicKey(toPoint(kp), curve.toSpec());
+ ECPrivateKey privkey = new RawECPrivateKey(toScalar(kp), curve.toSpec());
+ return new KeyPair(pubkey, privkey);
+ }
+
+ public static BigInteger recoverSignatureNonce(byte[] signature, byte[] data, BigInteger privkey, ECParameterSpec params, String hashAlgo, String sigType) {
+ // We do not know how to reconstruct those nonces so far.
+ // sigType.contains("ECKCDSA") || sigType.contains("ECNR") || sigType.contains("SM2")
+ if (!sigType.contains("ECDSA")) {
+ return null;
+ }
+ try {
+ int bitSize = params.getOrder().bitLength();
+ // Hash the data.
+ byte[] hash;
+ if (hashAlgo == null || hashAlgo.equals("NONE")) {
+ hash = data;
+ } else {
+ MessageDigest md = MessageDigest.getInstance(hashAlgo);
+ hash = md.digest(data);
+ }
+ // Trim bitSize of rightmost bits.
+ BigInteger hashInt = new BigInteger(1, hash);
+ int hashBits = hashInt.bitLength();
+ if (hashBits > bitSize) {
+ hashInt = hashInt.shiftRight(hashBits - bitSize);
+ }
+
+ // Parse signature
+ BigInteger[] sigPair;
+ if (sigType.contains("CVC") || sigType.contains("PLAIN")) {
+ sigPair = PlainDSAEncoding.INSTANCE.decode(params.getOrder(), signature);
+ } else {
+ sigPair = StandardDSAEncoding.INSTANCE.decode(params.getOrder(), signature);
+ }
+ BigInteger r = sigPair[0];
+ BigInteger s = sigPair[1];
+
+ BigInteger rd = privkey.multiply(r).mod(params.getOrder());
+ BigInteger hrd = hashInt.add(rd).mod(params.getOrder());
+ return s.modInverse(params.getOrder()).multiply(hrd).mod(params.getOrder());
+ } catch (NoSuchAlgorithmException | IOException | ArithmeticException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static EC_Params joinParams(EC_Params... params) {
+ List<EC_Params> paramList = new LinkedList<>();
+ short paramMask = 0;
+ int len = 0;
+ for (EC_Params param : params) {
+ if (param == null) {
+ continue;
+ }
+ int i = 0;
+ for (; i + 1 < paramList.size(); ++i) {
+ if (paramList.get(i + 1).getParams() == param.getParams()) {
+ throw new IllegalArgumentException();
+ }
+ if (paramList.get(i + 1).getParams() < param.getParams()) {
+ break;
+ }
+ }
+ paramList.add(i, param);
+ paramMask |= param.getParams();
+ len += param.numParams();
+ }
+
+ byte[][] res = new byte[len][];
+ int i = 0;
+ for (EC_Params param : params) {
+ for (byte[] data : param.getData()) {
+ res[i++] = data.clone();
+ }
+ }
+ return new EC_Params(paramMask, res);
+ }
+
+ public static EC_Params loadParams(short params, String named, String file) throws IOException {
+ EC_Params result = null;
+ if (file != null) {
+ result = new EC_Params(params);
+
+ FileInputStream in = new FileInputStream(file);
+ result.readCSV(in);
+ in.close();
+ } else if (named != null) {
+ if (params == EC_Consts.PARAMETER_W) {
+ result = EC_Store.getInstance().getObject(EC_Key.Public.class, named);
+ } else if (params == EC_Consts.PARAMETER_S) {
+ result = EC_Store.getInstance().getObject(EC_Key.Private.class, named);
+ }
+
+ if (result == null) {
+ result = EC_Store.getInstance().getObject(EC_Keypair.class, named);
+ }
+ }
+ return result;
+ }
+
+ public static ECKey loadKey(short params, String named, String file, AlgorithmParameterSpec spec) throws IOException {
+ if (params == EC_Consts.PARAMETERS_KEYPAIR) {
+ throw new IllegalArgumentException();
+ }
+ EC_Params param = loadParams(params, named, file);
+ if (param != null) {
+ if (params == EC_Consts.PARAMETER_W) {
+ return new RawECPublicKey(toPoint(param), (ECParameterSpec) spec);
+ } else if (params == EC_Consts.PARAMETER_S) {
+ return new RawECPrivateKey(toScalar(param), (ECParameterSpec) spec);
+ }
+ }
+ return null;
+ }
+
+ public static boolean equalKeyPairParameters(ECPrivateKey priv, ECPublicKey pub) {
+ if(priv == null || pub == null) {
+ return false;
+ }
+ return priv.getParams().getCurve().equals(pub.getParams().getCurve()) &&
+ priv.getParams().getCofactor() == pub.getParams().getCofactor() &&
+ priv.getParams().getGenerator().equals(pub.getParams().getGenerator()) &&
+ priv.getParams().getOrder().equals(pub.getParams().getOrder());
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/util/FileUtil.java b/common/src/main/java/cz/crcs/ectester/common/util/FileUtil.java
new file mode 100644
index 0000000..e6e319b
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/util/FileUtil.java
@@ -0,0 +1,99 @@
+package cz.crcs.ectester.common.util;
+
+import cz.crcs.ectester.common.output.TeeOutputStream;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class FileUtil {
+ private static Path appData = null;
+ public static String LIB_RESOURCE_DIR = "/cz/crcs/ectester/standalone/libs/jni/";
+
+ public static OutputStream openStream(String[] files) throws FileNotFoundException {
+ if (files == null) {
+ return null;
+ }
+ List<OutputStream> outs = new LinkedList<>();
+ for (String fileOut : files) {
+ outs.add(new FileOutputStream(fileOut));
+ }
+ return new TeeOutputStream(outs.toArray(new OutputStream[0]));
+ }
+
+ public static OutputStreamWriter openFiles(String[] files) throws FileNotFoundException {
+ if (files == null) {
+ return null;
+ }
+ return new OutputStreamWriter(openStream(files));
+ }
+
+ public static Path getAppData() {
+ if (appData != null) {
+ return appData;
+ }
+
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ appData = Paths.get(System.getenv("AppData"));
+ } else {
+ if (System.getProperty("os.name").startsWith("Linux")) {
+ String dataHome = System.getenv("XDG_DATA_HOME");
+ if (dataHome != null) {
+ appData = Paths.get(dataHome);
+ } else {
+ appData = Paths.get(System.getProperty("user.home"), ".local", "share");
+ }
+ } else {
+ appData = Paths.get(System.getProperty("user.home"), ".local", "share");
+ }
+ }
+ return appData;
+ }
+
+ public static boolean isNewer(URLConnection jarConn, Path realPath) throws IOException {
+ if (realPath.toFile().isFile()) {
+ long jarModified = jarConn.getLastModified();
+ long realModified = Files.getLastModifiedTime(realPath).toMillis();
+ return jarModified > realModified;
+ }
+ return true;
+ }
+
+ public static boolean writeNewer(String resourcePath, Path outPath) throws IOException {
+ URL reqURL = FileUtil.class.getResource(resourcePath);
+ if (reqURL == null) {
+ return false;
+ }
+ URLConnection reqConn = reqURL.openConnection();
+ if (isNewer(reqConn, outPath)) {
+ Files.copy(reqConn.getInputStream(), outPath, StandardCopyOption.REPLACE_EXISTING);
+ }
+ reqConn.getInputStream().close();
+ return true;
+ }
+
+ public static Path getLibDir() {
+ return getAppData().resolve("ECTesterStandalone");
+ }
+
+ public static Path getRequirementsDir() {
+ return getLibDir().resolve("lib");
+ }
+
+ public static String getLibSuffix() {
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ return "dll";
+ } else {
+ return "so";
+ }
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/common/util/Util.java b/common/src/main/java/cz/crcs/ectester/common/util/Util.java
new file mode 100644
index 0000000..5b0cd79
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/common/util/Util.java
@@ -0,0 +1,28 @@
+package cz.crcs.ectester.common.util;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class Util {
+ public static long convertTime(long nanos, String timeUnit) {
+ switch (timeUnit) {
+ default:
+ case "nano":
+ return nanos;
+ case "micro":
+ return nanos / 1000;
+ case "milli":
+ return nanos / 1000000;
+ }
+ }
+
+ public static int getVersion() {
+ String version = System.getProperty("java.version");
+ if(version.startsWith("1.")) {
+ version = version.substring(2, 3);
+ } else {
+ int dot = version.indexOf(".");
+ if(dot != -1) { version = version.substring(0, dot); }
+ } return Integer.parseInt(version);
+ }
+}
diff --git a/common/src/main/java/cz/crcs/ectester/data/EC_Store.java b/common/src/main/java/cz/crcs/ectester/data/EC_Store.java
new file mode 100644
index 0000000..ad25b1d
--- /dev/null
+++ b/common/src/main/java/cz/crcs/ectester/data/EC_Store.java
@@ -0,0 +1,404 @@
+package cz.crcs.ectester.data;
+
+import cz.crcs.ectester.common.ec.*;
+import cz.crcs.ectester.common.util.Util;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.ext.EntityResolver2;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+import java.util.function.Function;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Store {
+ private DocumentBuilder db;
+ private Map<String, EC_Category> categories;
+ private static EC_Store instance;
+
+ private EC_Store() {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
+ try {
+ SchemaFactory scf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ Schema sch = scf.newSchema(this.getClass().getResource("/cz/crcs/ectester/data/schema.xsd"));
+ dbf.setSchema(sch);
+ dbf.setNamespaceAware(true);
+ dbf.setIgnoringComments(true);
+ dbf.setXIncludeAware(true);
+ dbf.setIgnoringElementContentWhitespace(true);
+ db = dbf.newDocumentBuilder();
+ db.setErrorHandler(new ErrorHandler() {
+ @Override
+ public void warning(SAXParseException exception) throws SAXException {
+ System.err.println("EC_Store | Warning : " + exception);
+ }
+
+ @Override
+ public void error(SAXParseException exception) throws SAXException {
+ System.err.println("EC_Store | Error : " + exception);
+ }
+
+ @Override
+ public void fatalError(SAXParseException exception) throws SAXException {
+ System.err.println("EC_Store | Fatal : " + exception);
+ throw new SAXException(exception);
+ }
+ });
+ db.setEntityResolver(new EntityResolver2() {
+ @Override
+ public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException {
+ return null;
+ }
+
+ @Override
+ public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException {
+ InputSource is = new InputSource();
+ is.setSystemId(systemId);
+
+ InputStream bs;
+ // TODO: Figure out if this is correct for the older Java versions or also wrong.
+ if (Util.getVersion() <= 8) {
+ bs = getClass().getClass().getResourceAsStream("/cz/crcs/ectester/data/" + systemId);
+ } else {
+ bs = getClass().getResourceAsStream("/cz/crcs/ectester/data/" + systemId);
+ }
+ is.setByteStream(bs);
+ return is;
+ }
+
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+ return null;
+ }
+ });
+
+ parse();
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void parse() throws SAXException, ParserConfigurationException, IOException {
+
+ InputStream categories = this.getClass().getResourceAsStream("/cz/crcs/ectester/data/categories.xml");
+ if (categories == null) {
+ throw new IOException();
+ }
+ Document categoriesDoc = db.parse(categories);
+ categories.close();
+ categoriesDoc.normalize();
+
+ NodeList catList = categoriesDoc.getElementsByTagName("category");
+
+ this.categories = new TreeMap<>();
+ for (int i = 0; i < catList.getLength(); ++i) {
+ Node catNode = catList.item(i);
+ if (catNode instanceof Element) {
+ Element catElem = (Element) catNode;
+ Node name = catElem.getElementsByTagName("name").item(0);
+ Node dir = catElem.getElementsByTagName("directory").item(0);
+ Node desc = catElem.getElementsByTagName("desc").item(0);
+
+ EC_Category category = parseCategory(name.getTextContent(), dir.getTextContent(), desc.getTextContent());
+ this.categories.put(name.getTextContent(), category);
+ } else {
+ throw new SAXException("?");
+ }
+ }
+ }
+
+ private EC_Category parseCategory(String name, String dir, String desc) throws ParserConfigurationException, IOException, SAXException {
+
+ Map<String, EC_Data> objMap = new TreeMap<>();
+
+ InputStream curves = this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/curves.xml");
+ if (curves != null) {
+ Document curvesDoc = db.parse(curves);
+ curvesDoc.normalize();
+
+ NodeList curveList = curvesDoc.getElementsByTagName("curve");
+
+ for (int i = 0; i < curveList.getLength(); ++i) {
+ Node curveNode = curveList.item(i);
+ if (curveNode instanceof Element) {
+ Element curveElem = (Element) curveNode;
+ Node id = curveElem.getElementsByTagName("id").item(0);
+ Node bits = curveElem.getElementsByTagName("bits").item(0);
+ Node field = curveElem.getElementsByTagName("field").item(0);
+
+ NodeList descc = curveElem.getElementsByTagName("desc");
+ String descs = null;
+ if (descc.getLength() != 0) {
+ descs = descc.item(0).getTextContent();
+ }
+
+ byte alg;
+ if (field.getTextContent().equalsIgnoreCase("prime")) {
+ alg = EC_Consts.ALG_EC_FP;
+ } else {
+ alg = EC_Consts.ALG_EC_F2M;
+ }
+ short bitsize = Short.parseShort(bits.getTextContent());
+
+ EC_Curve curve = new EC_Curve(id.getTextContent(), bitsize, alg, descs);
+
+ InputStream csv = parseDataElement(dir, curveElem);
+ if (!curve.readCSV(csv)) {
+ throw new IOException("Invalid csv data." + id.getTextContent());
+ }
+ csv.close();
+
+ objMap.put(id.getTextContent(), curve);
+ } else {
+ throw new SAXException("?");
+ }
+ }
+ curves.close();
+ }
+
+ InputStream keys = this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/keys.xml");
+ if (keys != null) {
+ Document keysDoc = db.parse(keys);
+ keysDoc.normalize();
+
+ NodeList directs = keysDoc.getDocumentElement().getChildNodes();
+ for (int i = 0; i < directs.getLength(); ++i) {
+ Node direct = directs.item(i);
+ if (direct instanceof Element) {
+ Element elem = (Element) direct;
+
+ NodeList ids = elem.getElementsByTagName("id");
+ if (ids.getLength() != 1) {
+ throw new SAXException("key no id?");
+ }
+ String id = ids.item(0).getTextContent();
+
+ EC_Params result = parseKeylike(dir, elem);
+
+ objMap.put(id, result);
+ } else {
+ throw new SAXException("?");
+ }
+ }
+ keys.close();
+ }
+
+ InputStream results = this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/results.xml");
+ if (results != null) {
+ Document resultsDoc = db.parse(results);
+ resultsDoc.normalize();
+
+ NodeList directs = resultsDoc.getDocumentElement().getChildNodes();
+ for (int i = 0; i < directs.getLength(); ++i) {
+ Node direct = directs.item(i);
+ if (direct instanceof Element) {
+ Element elem = (Element) direct;
+
+ NodeList ids = elem.getElementsByTagName("id");
+ if (ids.getLength() != 1) {
+ throw new SAXException("result no id?");
+ }
+ String id = ids.item(0).getTextContent();
+
+ EC_Data result = parseResultlike(dir, elem);
+
+ objMap.put(id, result);
+ } else {
+ throw new SAXException("?");
+ }
+ }
+ results.close();
+ }
+
+ return new EC_Category(name, dir, desc, objMap);
+ }
+
+ private EC_Data parseResultlike(String dir, Element elem) throws SAXException, IOException {
+ String tag = elem.getTagName();
+ Node id = elem.getElementsByTagName("id").item(0);
+
+ NodeList descc = elem.getElementsByTagName("desc");
+ String descs = null;
+ if (descc.getLength() != 0) {
+ descs = descc.item(0).getTextContent();
+ }
+
+ Node curve = elem.getElementsByTagName("curve").item(0);
+
+ EC_Data result;
+ if (tag.equals("kaResult")) {
+ Node ka = elem.getElementsByTagName("ka").item(0);
+ Node onekey = elem.getElementsByTagName("onekey").item(0);
+ Node otherkey = elem.getElementsByTagName("otherkey").item(0);
+
+ result = new EC_KAResult(id.getTextContent(), ka.getTextContent(), curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs);
+ } else if (tag.equals("sigResult")) {
+ Node sig = elem.getElementsByTagName("sig").item(0);
+ Node signkey = elem.getElementsByTagName("signkey").item(0);
+ Node verifykey = elem.getElementsByTagName("verifykey").item(0);
+ NodeList datas = elem.getElementsByTagName("raw");
+ String data = null;
+ if (datas.getLength() != 0) {
+ data = datas.item(0).getTextContent();
+ }
+
+ result = new EC_SigResult(id.getTextContent(), sig.getTextContent(), curve.getTextContent(), signkey.getTextContent(), verifykey.getTextContent(), data, descs);
+ } else {
+ throw new SAXException("?");
+ }
+
+ InputStream csv = parseDataElement(dir, elem);
+ if (!result.readCSV(csv)) {
+ throw new IOException("Invalid csv data. " + id.getTextContent());
+ }
+ csv.close();
+
+ return result;
+ }
+
+ private EC_Params parseKeylike(String dir, Element elem) throws SAXException, IOException {
+ Node id = elem.getElementsByTagName("id").item(0);
+ Node curve = elem.getElementsByTagName("curve").item(0);
+
+ NodeList desc = elem.getElementsByTagName("desc");
+ String descs = null;
+ if (desc.getLength() != 0) {
+ descs = desc.item(0).getTextContent();
+ }
+
+ EC_Params result;
+ if (elem.getTagName().equals("pubkey")) {
+ result = new EC_Key.Public(id.getTextContent(), curve.getTextContent(), descs);
+ } else if (elem.getTagName().equals("privkey")) {
+ result = new EC_Key.Private(id.getTextContent(), curve.getTextContent(), descs);
+ } else if (elem.getTagName().equals("keypair")) {
+ result = new EC_Keypair(id.getTextContent(), curve.getTextContent(), descs);
+ } else {
+ throw new SAXException("?");
+ }
+
+ InputStream csv = parseDataElement(dir, elem);
+ if (!result.readCSV(csv)) {
+ throw new IOException("Invalid CSV data. " + id.getTextContent());
+ }
+ csv.close();
+
+ return result;
+ }
+
+ private InputStream parseDataElement(String dir, Element elem) throws SAXException {
+ NodeList file = elem.getElementsByTagName("file");
+ NodeList inline = elem.getElementsByTagName("inline");
+
+ InputStream csv;
+ if (file.getLength() == 1) {
+ csv = this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/" + file.item(0).getTextContent());
+ } else if (inline.getLength() == 1) {
+ csv = new ByteArrayInputStream(inline.item(0).getTextContent().getBytes());
+ } else {
+ throw new SAXException("?");
+ }
+ return csv;
+ }
+
+ public Map<String, EC_Category> getCategories() {
+ return Collections.unmodifiableMap(categories);
+ }
+
+ public EC_Category getCategory(String category) {
+ return categories.get(category);
+ }
+
+ public Map<String, EC_Data> getObjects(String category) {
+ EC_Category cat = categories.get(category);
+ if (cat != null) {
+ return cat.getObjects();
+ }
+ return null;
+ }
+
+ public <T extends EC_Data> Map<String, T> getObjects(Class<T> objClass, String category) {
+ EC_Category cat = categories.get(category);
+ if (cat != null) {
+ return cat.getObjects(objClass);
+ }
+ return null;
+ }
+
+ public <T extends EC_Data> T getObject(Class<T> objClass, String category, String id) {
+ EC_Category cat = categories.get(category);
+ if (cat != null) {
+ return cat.getObject(objClass, id);
+ }
+ return null;
+ }
+
+ public <T extends EC_Data> T getObject(Class<T> objClass, String query) {
+ int split = query.indexOf("/");
+ if (split < 0) {
+ return null;
+ }
+ return getObject(objClass, query.substring(0, split), query.substring(split + 1));
+ }
+
+ private static <T extends EC_Data> Map<EC_Curve, List<T>> mapKeyToCurve(Collection<T> data, Function<T, String> getter) {
+ Map<EC_Curve, List<T>> curves = new TreeMap<>();
+ for (T item : data) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, getter.apply(item));
+ List<T> curveKeys = curves.getOrDefault(curve, new LinkedList<>());
+ curveKeys.add(item);
+ curves.putIfAbsent(curve, curveKeys);
+ }
+ for (List<T> keyList : curves.values()) {
+ Collections.sort(keyList);
+ }
+ return curves;
+ }
+
+ public static <T extends EC_Key> Map<EC_Curve, List<T>> mapKeyToCurve(Collection<T> keys) {
+ return mapKeyToCurve(keys, EC_Key::getCurve);
+ }
+
+ public static Map<EC_Curve, List<EC_KAResult>> mapResultToCurve(Collection<EC_KAResult> results) {
+ return mapKeyToCurve(results, EC_KAResult::getCurve);
+ }
+
+ public static <T extends EC_Data> Map<String, List<T>> mapToPrefix(Collection<T> data) {
+ Map<String, List<T>> groups = new TreeMap<>();
+ for (T item : data) {
+ String prefix = item.getId().split("/")[0];
+ List<T> group = groups.getOrDefault(prefix, new LinkedList<>());
+ group.add(item);
+ groups.putIfAbsent(prefix, group);
+ }
+ for (List<T> itemList : groups.values()) {
+ Collections.sort(itemList);
+ }
+ return groups;
+ }
+
+ public static EC_Store getInstance() {
+ if (instance == null) {
+ instance = new EC_Store();
+ }
+ return instance;
+ }
+
+}