aboutsummaryrefslogtreecommitdiff
path: root/standalone/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 /standalone/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 'standalone/src/main/java')
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java949
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/consts/Ident.java88
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java130
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java55
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java141
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/BoringsslLib.java19
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/BotanLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java28
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/CryptoppLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/ECLibrary.java26
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/GcryptLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/IppcpLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/LibresslLib.java19
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/MatrixsslLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/MbedTLSLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/MscngLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java93
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java19
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java113
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/SunECLib.java28
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/TomcryptLib.java20
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java18
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java184
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java185
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java449
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java367
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java159
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java657
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java56
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java156
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java124
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java59
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java179
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java43
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java70
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/PerformanceTest.java109
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTest.java43
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTestable.java143
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java25
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java111
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java210
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java108
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java121
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java313
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java120
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneMiscSuite.java150
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java142
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java87
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java25
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java63
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java120
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java343
53 files changed, 6827 insertions, 0 deletions
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java
new file mode 100644
index 0000000..5d3bad2
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -0,0 +1,949 @@
+/*
+ * ECTester, tool for testing Elliptic curve cryptography implementations.
+ * Copyright (c) 2016-2018 Petr Svenda <petr@svenda.com>
+ * Copyright (c) 2016-2019 Jan Jancar <johny@neuromancer.sk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package cz.crcs.ectester.standalone;
+
+import cz.crcs.ectester.common.cli.*;
+import cz.crcs.ectester.common.ec.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.TestException;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.common.util.FileUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import cz.crcs.ectester.standalone.libs.*;
+import cz.crcs.ectester.standalone.output.TextTestWriter;
+import cz.crcs.ectester.standalone.output.XMLTestWriter;
+import cz.crcs.ectester.standalone.output.YAMLTestWriter;
+import cz.crcs.ectester.standalone.test.suites.*;
+import org.apache.commons.cli.*;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Standalone part of ECTester, a tool for testing Elliptic curve implementations in software libraries.
+ *
+ * @author Jan Jancar johny@neuromancer.sk
+ * @version v0.3.3
+ */
+public class ECTesterStandalone {
+ private ProviderECLibrary[] libs;
+ private Config cfg;
+
+ private Options opts = new Options();
+ private TreeParser optParser;
+ private TreeCommandLine cli;
+ public static final String VERSION = "v0.3.3";
+ private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility.";
+ private static final String LICENSE = "MIT Licensed\nCopyright © 2016-2019 Petr Svenda <petr@svenda.com>\nCopyright © 2016-2019 Jan Jancar <johny@neuromancer.sk>";
+ private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n";
+ private static final String CLI_FOOTER = "\n" + LICENSE;
+
+ public static String LIB_RESOURCE_DIR = "/cz/crcs/ectester/standalone/libs/jni/";
+
+ private void run(String[] args) {
+ try {
+ cli = parseArgs(args);
+
+ if (cli.hasOption("version")) {
+ CLITools.version(DESCRIPTION, LICENSE);
+ return;
+ } else if (cli.hasOption("help") || cli.getNext() == null) {
+ String command = cli.getOptionValue("help");
+ if (command == null) {
+ CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, optParser, CLI_FOOTER, true);
+ } else {
+ CLITools.help(CLI_HEADER, optParser, CLI_FOOTER, command);
+ }
+ return;
+ }
+
+ Path reqs = FileUtil.getRequirementsDir();
+ reqs.toFile().mkdirs();
+
+ if (!System.getProperty("os.name").startsWith("Windows")) {
+ FileUtil.writeNewer(LIB_RESOURCE_DIR + "lib_timing.so", reqs.resolve("lib_timing.so"));
+ System.load(reqs.resolve("lib_timing.so").toString());
+ }
+
+ List<ProviderECLibrary> libObjects = new LinkedList<>();
+ Class[] libClasses = new Class[]{SunECLib.class,
+ BouncyCastleLib.class,
+ TomcryptLib.class,
+ BotanLib.class,
+ CryptoppLib.class,
+ OpensslLib.class,
+ BoringsslLib.class,
+ GcryptLib.class,
+ MscngLib.class,
+ WolfCryptLib.class,
+ MbedTLSLib.class,
+ IppcpLib.class,
+ MatrixsslLib.class,
+ NettleLib.class,
+ LibresslLib.class};
+ for (Class c : libClasses) {
+ try {
+ libObjects.add((ProviderECLibrary) c.getDeclaredConstructor().newInstance());
+ } catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
+ InvocationTargetException e) {
+
+ }
+ }
+ libs = libObjects.toArray(new ProviderECLibrary[0]);
+
+ //TODO: push this further down to only initialize if necessary.
+ // and only initialize the chosen lib (so give libs a name in Java only)
+ for (ECLibrary lib : libs) {
+ try {
+ lib.initialize();
+ } catch (Exception ex) {
+ System.err.println(ex.getMessage());
+ }
+ }
+
+ cfg = new Config(libs);
+ if (!cfg.readOptions(cli)) {
+ return;
+ }
+
+ if (cli.isNext("list-libs")) {
+ listLibraries();
+ } else if (cli.isNext("list-data")) {
+ CLITools.listNamed(EC_Store.getInstance(), cli.getNext().getArg(0));
+ } else if (cli.isNext("list-suites")) {
+ listSuites();
+ } else if (cli.isNext("list-types")) {
+ listIdents();
+ } else if (cli.isNext("ecdh")) {
+ ecdh();
+ } else if (cli.isNext("ecdsa")) {
+ ecdsa();
+ } else if (cli.isNext("generate")) {
+ generate();
+ } else if (cli.isNext("test")) {
+ test();
+ } else if (cli.isNext("export")) {
+ export();
+ }
+
+ } catch (ParseException | ParserConfigurationException | IOException ex) {
+ System.err.println(ex.getMessage());
+ } catch (InvalidAlgorithmParameterException | InvalidParameterException e) {
+ System.err.println("Invalid algorithm parameter: " + e.getMessage());
+ } catch (NoSuchAlgorithmException nsaex) {
+ System.err.println("Algorithm not supported by the selected library: " + nsaex.getMessage());
+ } catch (InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private TreeCommandLine parseArgs(String[] args) throws ParseException {
+ Map<String, ParserOptions> actions = new TreeMap<>();
+
+ Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).numberOfArgs(1).build();
+ Option namedPublic = Option.builder("npub").longOpt("named-public").desc("Use a named public key, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).numberOfArgs(1).build();
+ Option filePublic = Option.builder("pub").longOpt("public").desc("Use a given public key from file.").hasArg().argName("pubkey").optionalArg(false).numberOfArgs(1).build();
+ OptionGroup publicKey = new OptionGroup();
+ publicKey.addOption(namedPublic);
+ publicKey.addOption(filePublic);
+ Option namedPrivate = Option.builder("npriv").longOpt("named-private").desc("Use a named private key, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).numberOfArgs(1).build();
+ Option filePrivate = Option.builder("priv").longOpt("private").desc("Use a given private key from file.").hasArg().argName("privkey").optionalArg(false).numberOfArgs(1).build();
+ OptionGroup privateKey = new OptionGroup();
+ privateKey.addOption(namedPrivate);
+ privateKey.addOption(filePrivate);
+ Option curveName = Option.builder("cn").longOpt("curve-name").desc("Use a named curve, search from curves supported by the library: <name>").hasArg().argName("name").optionalArg(false).numberOfArgs(1).build();
+ Option bits = Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").numberOfArgs(1).build();
+ Option output = Option.builder("o").longOpt("output").desc("Output into file <output_file>.").hasArgs().argName("output_file").optionalArg(false).numberOfArgs(1).build();
+ Option timeSource = Option.builder("ts").longOpt("time-source").desc("Use a given native timing source: {rdtsc, monotonic, monotonic-raw, cputime-process, cputime-thread, perfcount}").hasArgs().argName("source").optionalArg(false).numberOfArgs(1).build();
+
+ Options testOpts = new Options();
+ testOpts.addOption(bits);
+ testOpts.addOption(namedCurve);
+ testOpts.addOption(curveName);
+ testOpts.addOption(Option.builder("gt").longOpt("kpg-type").desc("Set the KeyPairGenerator object [type].").hasArg().argName("type").optionalArg(false).build());
+ testOpts.addOption(Option.builder("kt").longOpt("ka-type").desc("Set the KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build());
+ testOpts.addOption(Option.builder("st").longOpt("sig-type").desc("Set the Signature object [type].").hasArg().argName("type").optionalArg(false).build());
+ testOpts.addOption(Option.builder("f").longOpt("format").desc("Set the output format, one of text,yaml,xml.").hasArg().argName("format").optionalArg(false).build());
+ testOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF. Default is \"AES\".").hasArg().argName("algorithm").optionalArg(false).build());
+ List<Argument> testArgs = new LinkedList<>();
+ testArgs.add(new Argument("test-suite", "The test suite to run.", true));
+ ParserOptions test = new ParserOptions(new TreeParser(Collections.emptyMap(), true, testArgs), testOpts, "Test a library.");
+ actions.put("test", test);
+
+ Options ecdhOpts = new Options();
+ ecdhOpts.addOption(bits);
+ ecdhOpts.addOption(namedCurve);
+ ecdhOpts.addOption(curveName);
+ ecdhOpts.addOption(output);
+ ecdhOpts.addOption(timeSource);
+ ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build());
+ ecdhOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF. Default is \"AES\".").hasArg().argName("algorithm").optionalArg(false).build());
+ ecdhOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDH [amount] times.").build());
+ ecdhOpts.addOptionGroup(publicKey);
+ ecdhOpts.addOption(Option.builder().longOpt("fixed-private").desc("Perform ECDH with fixed private key.").build());
+ ecdhOpts.addOptionGroup(privateKey);
+ ecdhOpts.addOption(Option.builder().longOpt("fixed-public").desc("Perform ECDH with fixed public key.").build());
+ ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts, "Perform EC based KeyAgreement.");
+ actions.put("ecdh", ecdh);
+
+ Options ecdsaOpts = new Options();
+ ecdsaOpts.addOption(bits);
+ ecdsaOpts.addOption(namedCurve);
+ ecdsaOpts.addOption(curveName);
+ ecdsaOpts.addOption(output);
+ ecdsaOpts.addOption(timeSource);
+ ecdsaOpts.addOptionGroup(privateKey);
+ ecdsaOpts.addOptionGroup(publicKey);
+ ecdsaOpts.addOption(Option.builder().longOpt("fixed").desc("Perform all ECDSA with fixed keypair.").build());
+ ecdsaOpts.addOption(Option.builder("t").longOpt("type").desc("Set Signature object [type].").hasArg().argName("type").optionalArg(false).build());
+ ecdsaOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDSA [amount] times.").build());
+ ecdsaOpts.addOption(Option.builder("f").longOpt("file").hasArg().argName("file").optionalArg(false).desc("Input [file] to sign.").build());
+ ParserOptions ecdsa = new ParserOptions(new DefaultParser(), ecdsaOpts, "Perform EC based Signature.");
+ actions.put("ecdsa", ecdsa);
+
+ Options generateOpts = new Options();
+ generateOpts.addOption(bits);
+ generateOpts.addOption(namedCurve);
+ generateOpts.addOption(curveName);
+ generateOpts.addOption(output);
+ generateOpts.addOption(timeSource);
+ generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build());
+ generateOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPairGenerator object [type].").build());
+ ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts, "Generate EC keypairs.");
+ actions.put("generate", generate);
+
+ Options exportOpts = new Options();
+ exportOpts.addOption(bits);
+ exportOpts.addOption(output);
+ exportOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPair object [type].").build());
+ ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts, "Export default curve parameters.");
+ actions.put("export", export);
+
+ Options listDataOpts = new Options();
+ List<Argument> listDataArgs = new LinkedList<>();
+ listDataArgs.add(new Argument("what", "what to list.", false));
+ ParserOptions listData = new ParserOptions(new TreeParser(Collections.emptyMap(), false, listDataArgs), listDataOpts, "List/show contained EC domain parameters/keys.");
+ actions.put("list-data", listData);
+
+ Options listLibsOpts = new Options();
+ ParserOptions listLibs = new ParserOptions(new DefaultParser(), listLibsOpts, "List supported libraries.");
+ actions.put("list-libs", listLibs);
+
+ Options listSuitesOpts = new Options();
+ ParserOptions listSuites = new ParserOptions(new DefaultParser(), listSuitesOpts, "List supported test suites.");
+ actions.put("list-suites", listSuites);
+
+ Options listIdentsOpts = new Options();
+ ParserOptions listIdents = new ParserOptions(new DefaultParser(), listIdentsOpts, "List KeyPairGenerator, KeyAgreement and Signature types.");
+ actions.put("list-types", listIdents);
+
+ List<Argument> baseArgs = new LinkedList<>();
+ baseArgs.add(new Argument("lib", "What library to use.", false));
+ optParser = new TreeParser(actions, false, baseArgs);
+
+ opts.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build());
+ opts.addOption(Option.builder("h").longOpt("help").desc("Print help(about <command>).").hasArg().argName("command").optionalArg(true).build());
+ opts.addOption(Option.builder("C").longOpt("color").desc("Print stuff with color, requires ANSI terminal.").build());
+
+ return optParser.parse(opts, args);
+ }
+
+ /**
+ *
+ */
+ private void listLibraries() {
+ for (ProviderECLibrary lib : libs) {
+ if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) {
+ System.out.println("\t- " + Colors.bold(lib.name()));
+ System.out.println(Colors.bold("\t\t- Version: ") + String.format("%f", lib.getProvider().getVersion()));
+ System.out.println(Colors.bold("\t\t- Supports native timing: ") + lib.getNativeTimingSupport().toString());
+ Set<KeyPairGeneratorIdent> kpgs = lib.getKPGs();
+ if (!kpgs.isEmpty()) {
+ System.out.println(Colors.bold("\t\t- KeyPairGenerators: ") + String.join(", ", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList())));
+ }
+ Set<KeyAgreementIdent> eckas = lib.getKAs();
+ if (!eckas.isEmpty()) {
+ System.out.println(Colors.bold("\t\t- KeyAgreements: ") + String.join(", ", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList())));
+ }
+ Set<SignatureIdent> sigs = lib.getSigs();
+ if (!sigs.isEmpty()) {
+ System.out.println(Colors.bold("\t\t- Signatures: ") + String.join(", ", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList())));
+ }
+ Set<String> curves = lib.getCurves();
+ if (!curves.isEmpty()) {
+ System.out.println(Colors.bold("\t\t- Curves: ") + String.join(", ", curves));
+ }
+ System.out.println();
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void listSuites() {
+ StandaloneTestSuite[] suites = new StandaloneTestSuite[]{
+ new StandaloneDefaultSuite(null, null, null),
+ new StandaloneTestVectorSuite(null, null, null),
+ new StandaloneInvalidSuite(null, null, null),
+ new StandaloneWrongSuite(null, null, null),
+ new StandaloneDegenerateSuite(null, null, null),
+ new StandaloneCofactorSuite(null, null, null),
+ new StandaloneEdgeCasesSuite(null, null, null),
+ new StandaloneSignatureSuite(null, null, null),
+ new StandaloneCompositeSuite(null, null, null),
+ new StandaloneTwistSuite(null, null, null),
+ new StandaloneMiscSuite(null, null, null),
+ new StandalonePerformanceSuite(null, null, null)};
+ for (StandaloneTestSuite suite : suites) {
+ System.out.println(" - " + suite.getName());
+ for (String line : suite.getDescription()) {
+ System.out.println("\t" + line);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void listIdents() {
+ System.out.println(Colors.bold("\t- KeyPairGenerator"));
+ for (KeyPairGeneratorIdent kpgIdent : KeyPairGeneratorIdent.list()) {
+ System.out.println("\t\t- " + Colors.underline(kpgIdent.getName()) + " " + kpgIdent.toString());
+ }
+ System.out.println(Colors.bold("\t- KeyAgreement"));
+ for (KeyAgreementIdent kaIdent : KeyAgreementIdent.list()) {
+ System.out.println("\t\t- " + Colors.underline(kaIdent.getName()) + " " + kaIdent.toString());
+ }
+ System.out.println(Colors.bold("\t- Signature"));
+ for (SignatureIdent sigIdent : SignatureIdent.list()) {
+ System.out.println("\t\t- " + Colors.underline(sigIdent.getName()) + " " + sigIdent.toString());
+ }
+ }
+
+ /**
+ *
+ */
+ private void ecdh() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException {
+ ProviderECLibrary lib = cfg.selected;
+
+ String algo = cli.getOptionValue("ecdh.type", "ECDH");
+ String keyAlgo = cli.getOptionValue("ecdh.key-type", "AES");
+ KeyAgreementIdent kaIdent = lib.getKAs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(null);
+
+ String baseAlgo;
+ if (algo.contains("with")) {
+ baseAlgo = algo.split("with")[0];
+ } else {
+ baseAlgo = algo;
+ }
+
+ KeyPairGeneratorIdent kpIdent = lib.getKPGs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains(baseAlgo))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains("ECDH"))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst()
+ .orElse(null))));
+
+ if (kaIdent == null || kpIdent == null) {
+ throw new NoSuchAlgorithmException(algo);
+ }
+
+ KeyAgreement ka = kaIdent.getInstance(lib.getProvider());
+ KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ AlgorithmParameterSpec spec = null;
+ if (cli.hasOption("ecdh.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("ecdh.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("ecdh.named-curve")) {
+ String curveName = cli.getOptionValue("ecdh.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ spec = curve.toSpec();
+ kpg.initialize(spec);
+ } else if (cli.hasOption("ecdh.curve-name")) {
+ String curveName = cli.getOptionValue("ecdh.curve-name");
+ spec = new ECGenParameterSpec(curveName);
+ kpg.initialize(spec);
+ }
+
+ if (cli.hasOption("ecdh.time-source")) {
+ if (!lib.setNativeTimingType(cli.getOptionValue("ecdh.time-source"))) {
+ System.err.println("Couldn't set native time source.");
+ return;
+ }
+ }
+
+ PrintStream out;
+ if (cli.hasOption("ecdh.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdh.output")));
+ } else {
+ out = System.out;
+ }
+
+ String timeUnit = "nano";
+ if (!lib.getNativeTimingSupport().isEmpty()) {
+ timeUnit = lib.getNativeTimingUnit();
+ }
+
+ String hashAlgo = kaIdent.getBaseAlgo() != null ? String.format("[%s]", kaIdent.getBaseAlgo()) : "[NONE]";
+ out.println(String.format("index;time[%s];pubW;privS;secret%s", timeUnit, hashAlgo));
+
+ KeyPair one = null;
+ if (cli.hasOption("ecdh.fixed-private") && !cli.hasOption("ecdh.named-private") && !cli.hasOption("ecdh.private")) {
+ one = kpg.genKeyPair();
+ }
+ KeyPair other = null;
+ if (cli.hasOption("ecdh.fixed-public") && !cli.hasOption("ecdh.named-public") && !cli.hasOption("ecdh.public")) {
+ other = kpg.genKeyPair();
+ }
+
+ ECPrivateKey privkey = (ECPrivateKey) ECUtil.loadKey(EC_Consts.PARAMETER_S, cli.getOptionValue("ecdh.named-private"), cli.getOptionValue("ecdh.private"), spec);
+ ECPublicKey pubkey = (ECPublicKey) ECUtil.loadKey(EC_Consts.PARAMETER_W, cli.getOptionValue("ecdh.named-public"), cli.getOptionValue("ecdh.public"), spec);
+
+ int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1"));
+ for (int i = 0; i < amount || amount == 0; ++i) {
+ if (!cli.hasOption("ecdh.fixed-private") && !cli.hasOption("ecdh.named-private") && !cli.hasOption("ecdh.private")) {
+ one = kpg.genKeyPair();
+ }
+ if (!cli.hasOption("ecdh.fixed-public") && !cli.hasOption("ecdh.named-public") && !cli.hasOption("ecdh.public")) {
+ other = kpg.genKeyPair();
+ }
+
+ if (!cli.hasOption("ecdh.named-private") && !cli.hasOption("ecdh.private")) {
+ privkey = (ECPrivateKey) one.getPrivate();
+ }
+
+ if (!cli.hasOption("ecdh.named-public") && !cli.hasOption("ecdh.public")) {
+ pubkey = (ECPublicKey) other.getPublic();
+ }
+
+ long elapsed = -System.nanoTime();
+ if (spec instanceof ECParameterSpec && lib instanceof NativeECLibrary) {
+ ka.init(privkey, spec);
+ } else {
+ ka.init(privkey);
+ }
+ ka.doPhase(pubkey, true);
+ elapsed += System.nanoTime();
+ SecretKey derived;
+ byte[] result;
+ elapsed -= System.nanoTime();
+ if (kaIdent.requiresKeyAlgo()) {
+ derived = ka.generateSecret(keyAlgo);
+ result = derived.getEncoded();
+ } else {
+ result = ka.generateSecret();
+ }
+ elapsed += System.nanoTime();
+ if (!lib.getNativeTimingSupport().isEmpty()) {
+ elapsed = lib.getLastNativeTiming();
+ }
+ ka = kaIdent.getInstance(lib.getProvider());
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
+ String dh = ByteUtil.bytesToHex(result, false);
+ out.println(String.format("%d;%d;%s;%s;%s", i, elapsed, pub, priv, dh));
+ }
+
+ if (cli.hasOption("ecdh.output")) {
+ out.close();
+ }
+ }
+
+ /**
+ *
+ */
+ private void ecdsa() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException, SignatureException {
+ byte[] data;
+ String dataString;
+ if (cli.hasOption("ecdsa.file")) {
+ String fileName = cli.getOptionValue("ecdsa.file");
+ File in = new File(fileName);
+ long len = in.length();
+ if (len == 0) {
+ throw new FileNotFoundException(fileName);
+ }
+ data = Files.readAllBytes(in.toPath());
+ dataString = "";
+ } else {
+ Random random = new Random();
+ data = new byte[32];
+ random.nextBytes(data);
+ dataString = ByteUtil.bytesToHex(data, false);
+ }
+ ProviderECLibrary lib = cfg.selected;
+ String algo = cli.getOptionValue("ecdsa.type", "ECDSA");
+ SignatureIdent sigIdent = lib.getSigs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(null);
+
+ String baseAlgo;
+ if (algo.contains("with")) {
+ baseAlgo = algo.split("with")[1];
+ } else {
+ baseAlgo = algo;
+ }
+ KeyPairGeneratorIdent kpIdent = lib.getKPGs().stream()
+ .filter((ident) -> ident.contains(algo))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains(baseAlgo))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains("ECDSA"))
+ .findFirst()
+ .orElse(lib.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst()
+ .orElse(null))));
+
+ if (sigIdent == null || kpIdent == null) {
+ throw new NoSuchAlgorithmException(algo);
+ }
+ Signature sig = sigIdent.getInstance(lib.getProvider());
+ KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ ECParameterSpec spec = null;
+ if (cli.hasOption("ecdsa.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("ecdsa.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("ecdsa.named-curve")) {
+ String curveName = cli.getOptionValue("ecdsa.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ spec = curve.toSpec();
+ kpg.initialize(spec);
+ } else if (cli.hasOption("ecdsa.curve-name")) {
+ String curveName = cli.getOptionValue("ecdsa.curve-name");
+ kpg.initialize(new ECGenParameterSpec(curveName));
+ }
+
+ if (cli.hasOption("ecdsa.time-source")) {
+ if (!lib.setNativeTimingType(cli.getOptionValue("ecdsa.time-source"))) {
+ System.err.println("Couldn't set native time source.");
+ return;
+ }
+ }
+
+ PrintStream out;
+ if (cli.hasOption("ecdsa.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdsa.output")));
+ } else {
+ out = System.out;
+ }
+
+ String timeUnit = "nano";
+ if (!lib.getNativeTimingSupport().isEmpty()) {
+ timeUnit = lib.getNativeTimingUnit();
+ }
+
+ String hashAlgoOut = sigIdent.getHashAlgo() != null ? String.format("[%s]", sigIdent.getHashAlgo()) : "";
+ out.println(String.format("index;signTime[%s];verifyTime[%s];data;pubW;privS;signature%s;nonce;verified", timeUnit, timeUnit, hashAlgoOut));
+
+ ECPrivateKey privkey = (ECPrivateKey) ECUtil.loadKey(EC_Consts.PARAMETER_S, cli.getOptionValue("ecdsa.named-private"), cli.getOptionValue("ecdsa.private"), spec);
+ ECPublicKey pubkey = (ECPublicKey) ECUtil.loadKey(EC_Consts.PARAMETER_W, cli.getOptionValue("ecdsa.named-public"), cli.getOptionValue("ecdsa.public"), spec);
+
+ KeyPair one;
+ if (cli.hasOption("ecdsa.fixed")) {
+ one = kpg.genKeyPair();
+ if (!cli.hasOption("ecdsa.named-private")) {
+ privkey = (ECPrivateKey) one.getPrivate();
+ }
+ if (!cli.hasOption("ecdsa.named-public")) {
+ pubkey = (ECPublicKey) one.getPublic();
+ }
+ }
+
+
+ int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1"));
+ for (int i = 0; i < amount || amount == 0; ++i) {
+ if ((!cli.hasOption("ecdsa.named-private") || !cli.hasOption("ecdsa.named-public")) && !cli.hasOption("ecdsa.fixed")) {
+ one = kpg.genKeyPair();
+
+ if (!cli.hasOption("ecdsa.named-private")) {
+ privkey = (ECPrivateKey) one.getPrivate();
+ }
+ if (!cli.hasOption("ecdsa.named-public")) {
+ pubkey = (ECPublicKey) one.getPublic();
+ }
+ }
+
+ sig.initSign(privkey);
+ sig.update(data);
+
+ long signTime = -System.nanoTime();
+ byte[] signature = sig.sign();
+ signTime += System.nanoTime();
+ if (!lib.getNativeTimingSupport().isEmpty()) {
+ signTime = lib.getLastNativeTiming();
+ }
+
+ sig.initVerify(pubkey);
+ sig.update(data);
+
+ long verifyTime = -System.nanoTime();
+ boolean verified = sig.verify(signature);
+ verifyTime += System.nanoTime();
+ if (!lib.getNativeTimingSupport().isEmpty()) {
+ verifyTime = lib.getLastNativeTiming();
+ }
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
+ String sign = ByteUtil.bytesToHex(signature, false);
+ String k = "";
+ ECParameterSpec kSpec = spec;
+ if (kSpec == null) {
+ kSpec = privkey.getParams();
+ }
+ if (kSpec != null) {
+ // Parse the types out of SignatureIdent.
+ String hashAlgo = sigIdent.getHashAlgo();
+ String sigType = sigIdent.getSigType();
+ if (sigType == null) {
+ sigType = sigIdent.toString();
+ }
+
+ BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, privkey.getS(), kSpec, hashAlgo, sigType);
+ if (kValue != null) {
+ k = ByteUtil.bytesToHex(kValue.toByteArray(), false);
+ }
+ }
+ out.println(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d", i, signTime, verifyTime, dataString, pub, priv, sign, k, verified ? 1 : 0));
+ }
+
+ if (cli.hasOption("ecdsa.output")) {
+ out.close();
+ }
+ }
+
+ /**
+ *
+ */
+ private void generate() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, FileNotFoundException {
+ ProviderECLibrary lib = cfg.selected;
+ KeyPairGeneratorIdent ident = null;
+ String algo = cli.getOptionValue("generate.type", "EC");
+ for (KeyPairGeneratorIdent kpIdent : lib.getKPGs()) {
+ if (kpIdent.contains(algo)) {
+ ident = kpIdent;
+ break;
+ }
+ }
+ if (ident == null) {
+ throw new NoSuchAlgorithmException(algo);
+ }
+ KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
+ if (cli.hasOption("generate.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("generate.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("generate.named-curve")) {
+ String curveName = cli.getOptionValue("generate.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ kpg.initialize(curve.toSpec());
+ } else if (cli.hasOption("generate.curve-name")) {
+ String curveName = cli.getOptionValue("generate.curve-name");
+ kpg.initialize(new ECGenParameterSpec(curveName));
+ }
+
+ if (cli.hasOption("generate.time-source")) {
+ if (!lib.setNativeTimingType(cli.getOptionValue("generate.time-source"))) {
+ System.err.println("Couldn't set native time source.");
+ return;
+ }
+ }
+
+ String timeUnit = "nano";
+ if (!lib.getNativeTimingSupport().isEmpty()) {
+ timeUnit = lib.getNativeTimingUnit();
+ }
+
+ PrintStream out;
+ if (cli.hasOption("generate.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("generate.output")));
+ } else {
+ out = System.out;
+ }
+
+ out.println(String.format("index;time[%s];pubW;privS", timeUnit));
+
+ int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1"));
+ for (int i = 0; i < amount || amount == 0; ++i) {
+ long elapsed = -System.nanoTime();
+ KeyPair kp = kpg.genKeyPair();
+ elapsed += System.nanoTime();
+ if (!lib.getNativeTimingSupport().isEmpty()) {
+ elapsed = lib.getLastNativeTiming();
+ }
+ ECPublicKey publicKey = (ECPublicKey) kp.getPublic();
+ ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false);
+ out.println(String.format("%d;%d;%s;%s", i, elapsed, pub, priv));
+ }
+
+ if (cli.hasOption("generate.output")) {
+ out.close();
+ }
+ }
+
+ /**
+ *
+ */
+ private void test() throws TestException, ParserConfigurationException {
+ TestWriter writer;
+ switch (cli.getOptionValue("test.format", "text").toLowerCase()) {
+ case "yaml":
+ case "yml":
+ writer = new YAMLTestWriter(System.out);
+ break;
+ case "xml":
+ writer = new XMLTestWriter(System.out);
+ break;
+ case "text":
+ default:
+ writer = new TextTestWriter(System.out);
+ break;
+ }
+
+ StandaloneTestSuite suite;
+
+ switch (cli.getArg(0).toLowerCase()) {
+ case "test-vectors":
+ suite = new StandaloneTestVectorSuite(writer, cfg, cli);
+ break;
+ case "wrong":
+ suite = new StandaloneWrongSuite(writer, cfg, cli);
+ break;
+ case "degenerate":
+ suite = new StandaloneDegenerateSuite(writer, cfg, cli);
+ break;
+ case "cofactor":
+ suite = new StandaloneCofactorSuite(writer, cfg, cli);
+ break;
+ case "composite":
+ suite = new StandaloneCompositeSuite(writer, cfg, cli);
+ break;
+ case "invalid":
+ suite = new StandaloneInvalidSuite(writer, cfg, cli);
+ break;
+ case "edge-cases":
+ suite = new StandaloneEdgeCasesSuite(writer, cfg, cli);
+ break;
+ case "signature":
+ suite = new StandaloneSignatureSuite(writer, cfg, cli);
+ break;
+ case "twist":
+ suite = new StandaloneTwistSuite(writer, cfg, cli);
+ break;
+ case "miscellaneous":
+ suite = new StandaloneMiscSuite(writer, cfg, cli);
+ break;
+ case "performance":
+ suite = new StandalonePerformanceSuite(writer, cfg, cli);
+ break;
+ case "default":
+ default:
+ suite = new StandaloneDefaultSuite(writer, cfg, cli);
+ }
+
+ suite.run();
+ }
+
+ /**
+ *
+ */
+ private void export() throws NoSuchAlgorithmException, IOException {
+ ProviderECLibrary lib = cfg.selected;
+ KeyPairGeneratorIdent ident = null;
+ String algo = cli.getOptionValue("export.type", "EC");
+ for (KeyPairGeneratorIdent kpIdent : lib.getKPGs()) {
+ if (kpIdent.contains(algo)) {
+ ident = kpIdent;
+ break;
+ }
+ }
+ if (ident == null) {
+ throw new NoSuchAlgorithmException(algo);
+ }
+ KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
+ if (cli.hasOption("export.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("export.bits"));
+ kpg.initialize(bits);
+ }
+ KeyPair kp = kpg.genKeyPair();
+ ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+ ECParameterSpec params = privateKey.getParams();
+ System.out.println(params);
+ EC_Curve curve = EC_Curve.fromSpec(params);
+ curve.writeCSV(System.out);
+ }
+
+ public static void main(String[] args) {
+ ECTesterStandalone app = new ECTesterStandalone();
+ app.run(args);
+ }
+
+
+ /**
+ *
+ */
+ public static class Config {
+ private ProviderECLibrary[] libs;
+ public ProviderECLibrary selected = null;
+ public boolean color = false;
+
+ public Config(ProviderECLibrary[] libs) {
+ this.libs = libs;
+ }
+
+ boolean readOptions(TreeCommandLine cli) {
+ color = cli.hasOption("color");
+ Colors.enabled = color;
+
+ String next = cli.getNextName();
+
+ if (cli.isNext("generate") || cli.isNext("export") || cli.isNext("ecdh") || cli.isNext("ecdsa") || cli.isNext("test")) {
+ if (!cli.hasArg(-1)) {
+ System.err.println("Missing library name argument.");
+ return false;
+ }
+
+ boolean hasBits = cli.hasOption(next + ".bits");
+ boolean hasNamedCurve = cli.hasOption(next + ".named-curve");
+ boolean hasCurveName = cli.hasOption(next + ".curve-name");
+ if (hasBits ^ hasNamedCurve ? hasCurveName : hasBits) {
+ System.err.println("You can only specify bitsize or a named curve/curve name, nor both.");
+ return false;
+ }
+
+ if (hasCurveName && (cli.hasOption(next + ".named-public") || cli.hasOption(next + ".named-private") || cli.hasOption(next + ".public") || cli.hasOption(next + ".private"))) {
+ System.err.println("Cannot specify key with a curve name switch, needs explicit parameteres.");
+ return false;
+ }
+ }
+
+ if (!cli.isNext("list-data") && !cli.isNext("list-suites") && !cli.isNext("list-types")) {
+ String libraryName = cli.getArg(-1);
+ if (libraryName != null) {
+ List<ProviderECLibrary> matchedLibs = new LinkedList<>();
+ for (ProviderECLibrary lib : libs) {
+ if (lib.isInitialized() && lib.name().toLowerCase().contains(libraryName.toLowerCase())) {
+ matchedLibs.add(lib);
+ }
+ }
+ if (matchedLibs.size() == 0) {
+ System.err.println("No library " + libraryName + " found.");
+ return false;
+ } else if (matchedLibs.size() > 1) {
+ System.err.println("Multiple matching libraries found: " + String.join(",", matchedLibs.stream().map(ECLibrary::name).collect(Collectors.toList())));
+ return false;
+ } else {
+ selected = matchedLibs.get(0);
+ }
+ }
+ }
+
+ if (cli.hasOption("test.format")) {
+ String fmt = cli.getOptionValue("test.format");
+ String[] formats = new String[]{"text", "xml", "yaml", "yml"};
+ if (!Arrays.asList(formats).contains(fmt.toLowerCase())) {
+ System.err.println("Invalid format specified.");
+ return false;
+ }
+ }
+
+ if (cli.isNext("ecdh")) {
+ if ((cli.hasOption("ecdh.public") || cli.hasOption("ecdh.private")) && !cli.hasOption("ecdh.named-curve")) {
+ System.err.println("Need to specify a named curve when specifying public/private key in file.");
+ return false;
+ }
+ }
+
+ if (cli.isNext("ecdsa")) {
+ if ((cli.hasOption("ecdsa.public") || cli.hasOption("ecdsa.private")) && !cli.hasOption("ecdsa.named-curve")) {
+ System.err.println("Need to specify a named curve when specifying public/private key in file.");
+ return false;
+ }
+ }
+
+ if (cli.isNext("generate") || cli.isNext("ecdh") || cli.isNext("ecdsa")) {
+ if (cli.hasOption(next + ".time-source")) {
+ String source = cli.getOptionValue(next + ".time-source");
+ if (!selected.getNativeTimingSupport().contains(source)) {
+ System.err.println(String.format("Time source %s unavailable for library %s.", source, selected.name()));
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/Ident.java b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/Ident.java
new file mode 100644
index 0000000..fcc811d
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/Ident.java
@@ -0,0 +1,88 @@
+package cz.crcs.ectester.standalone.consts;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.*;
+import java.util.function.BiFunction;
+
+public abstract class Ident {
+ Set<String> idents;
+ String name;
+
+ public Ident(String name, String... aliases) {
+ this.name = name;
+ this.idents = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+ this.idents.add(name);
+ this.idents.addAll(Arrays.asList(aliases));
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set<String> getIdents() {
+ return Collections.unmodifiableSet(idents);
+ }
+
+ public boolean contains(String other) {
+ return name.equals(other) || idents.contains(other);
+ }
+
+ public boolean containsAny(List<String> others) {
+ for(String other : others) {
+ if(name.equals(other) || idents.contains(other)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ <T> T getInstance(BiFunction<String, Provider, T> getter, Provider provider) throws NoSuchAlgorithmException {
+ T instance = null;
+ try {
+ instance = getter.apply(name, provider);
+ } catch (Exception ignored) {
+ ignored.printStackTrace();
+ }
+
+ if (instance == null) {
+ for (String alias : idents) {
+ try {
+ instance = getter.apply(alias, provider);
+ if (instance != null) {
+ break;
+ }
+ } catch (Exception ignored) {
+ ignored.printStackTrace();
+ }
+ }
+ }
+
+ if (instance == null) {
+ throw new NoSuchAlgorithmException(name);
+ }
+ return instance;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Ident)) {
+ return false;
+ }
+ Ident other = (Ident) obj;
+ return idents.equals(other.getIdents());
+ }
+
+ @Override
+ public int hashCode() {
+ return idents.hashCode() + 37;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + String.join(" | ", idents) + ")";
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
new file mode 100644
index 0000000..60c60e8
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
@@ -0,0 +1,130 @@
+package cz.crcs.ectester.standalone.consts;
+
+import javax.crypto.KeyAgreement;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class KeyAgreementIdent extends Ident {
+ private boolean requiresKeyAlgo;
+ private String kdf;
+ private String algo;
+
+ private static final List<KeyAgreementIdent> ALL = new LinkedList<>();
+
+ static {
+ //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
+ // Basic ECDH and ECDHC (plain/raw)
+ ALL.add(new KeyAgreementIdent("ECDH"));
+ ALL.add(new KeyAgreementIdent("ECDHC", "ECCDH"));
+ // ECDH and ECDHC with SHA as KDF, OIDs from RFC 3278
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF", true, "1.3.133.16.840.63.0.2"));
+ ALL.add(new KeyAgreementIdent("ECCDHwithSHA1KDF", true, "1.3.133.16.840.63.0.3"));
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA224KDF", true, "1.3.132.1.11.0"));
+ ALL.add(new KeyAgreementIdent("ECCDHwithSHA224KDF", true, "1.3.132.1.14.0"));
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA256KDF", true, "1.3.132.1.11.1"));
+ ALL.add(new KeyAgreementIdent("ECCDHwithSHA256KDF", true, "1.3.132.1.14.1"));
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA384KDF", true, "1.3.132.1.11.2"));
+ ALL.add(new KeyAgreementIdent("ECCDHwithSHA384KDF", true, "1.3.132.1.14.2"));
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF", true, "1.3.132.1.11.3"));
+ ALL.add(new KeyAgreementIdent("ECCDHwithSHA512KDF", true, "1.3.132.1.14.3"));
+ // Microsoft specific KDF
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF(CNG)"));
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA256KDF(CNG)"));
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA384KDF(CNG)"));
+ ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF(CNG)"));
+ // CKDF requires custom AlgorithmParameterSpec (only BouncyCastle)
+ //ALL.add(new KeyAgreementIdent("ECDHwithSHA1CKDF", true));
+ //ALL.add(new KeyAgreementIdent("ECCDHwithSHA1CKDF", true));
+ //ALL.add(new KeyAgreementIdent("ECDHwithSHA256CKDF", true));
+ //ALL.add(new KeyAgreementIdent("ECCDHwithSHA256CKDF", true));
+ //ALL.add(new KeyAgreementIdent("ECDHwithSHA384CKDF", true));
+ //ALL.add(new KeyAgreementIdent("ECCDHwithSHA384CKDF", true));
+ //ALL.add(new KeyAgreementIdent("ECDHwithSHA512CKDF", true));
+ //ALL.add(new KeyAgreementIdent("ECCDHwithSHA512CKDF", true));
+ // ECMQV - Disable for now as it needs diferent params(too different from DH)
+ //ALL.add(new KeyAgreementIdent("ECMQV"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA1KDF", true));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA224KDF", true));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA256KDF", true));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA354KDF", true));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA512KDF", true));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA1CKDF", true, "1.3.133.16.840.63.0.16"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA224CKDF", true, "1.3.132.1.15.0"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA256CKDF", true, "1.3.132.1.15.1"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA384CKDF", true, "1.3.132.1.15.2"));
+ //ALL.add(new KeyAgreementIdent("ECMQVwithSHA512CKDF", true, "1.3.132.1.15.3"));
+ // ECVKO - Disable for now as it needs diferent params(too different from DH)
+ //ALL.add(new KeyAgreementIdent("ECVKO", "ECGOST3410", "1.2.643.2.2.19", "GOST-3410-2001", "1.2.643.2.2.96"));
+ //ALL.add(new KeyAgreementIdent("ECVKO256", "ECGOST3410-2012-256", "1.2.643.7.1.1.6.1", "1.2.643.7.1.1.1.1"));
+ //ALL.add(new KeyAgreementIdent("ECVKO512", "ECGOST3410-2012-512", "1.2.643.7.1.1.6.2", "1.2.643.7.1.1.1.2"));
+ }
+
+ public static KeyAgreementIdent get(String ident) {
+ for (KeyAgreementIdent ka : ALL) {
+ if (ka.getIdents().contains(ident)) {
+ return ka;
+ }
+ }
+ return null;
+ }
+
+ public static List<KeyAgreementIdent> list() {
+ return Collections.unmodifiableList(ALL);
+ }
+
+ private KeyAgreementIdent(String name, String... aliases) {
+ super(name, aliases);
+ if (name.contains("with")) {
+ int split = name.indexOf("with");
+ this.algo = name.substring(0, split);
+ this.kdf = name.substring(split + 4);
+ } else {
+ for (String alias : aliases) {
+ if (alias.contains("with")) {
+ int split = alias.indexOf("with");
+ this.algo = alias.substring(0, split);
+ this.kdf = alias.substring(split + 4);
+ break;
+ }
+ }
+ if (this.algo == null) {
+ this.algo = name;
+ }
+ }
+ }
+
+ private KeyAgreementIdent(String name, boolean requiresKeyAlgo, String... aliases) {
+ this(name, aliases);
+ this.requiresKeyAlgo = requiresKeyAlgo;
+ }
+
+ public boolean requiresKeyAlgo() {
+ return requiresKeyAlgo;
+ }
+
+ public String getKdfAlgo() {
+ return kdf;
+ }
+
+ public String getBaseAlgo() {
+ return algo;
+ }
+
+ public KeyAgreement getInstance(Provider provider) throws NoSuchAlgorithmException {
+ KeyAgreement instance = getInstance((algorithm, provider1) -> {
+ try {
+ return KeyAgreement.getInstance(algorithm, provider1);
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ }, provider);
+ instance.getProvider();
+ return instance;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java
new file mode 100644
index 0000000..83eef75
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java
@@ -0,0 +1,55 @@
+package cz.crcs.ectester.standalone.consts;
+
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class KeyPairGeneratorIdent extends Ident {
+ private static final List<KeyPairGeneratorIdent> ALL = new LinkedList<>();
+
+ static {
+ ALL.add(new KeyPairGeneratorIdent("EC"));
+ ALL.add(new KeyPairGeneratorIdent("ECDH"));
+ ALL.add(new KeyPairGeneratorIdent("ECDSA"));
+ ALL.add(new KeyPairGeneratorIdent("ECDHC"));
+ ALL.add(new KeyPairGeneratorIdent("ECMQV"));
+ //ALL.add(new KeyPairGeneratorIdent("ECGOST3410"));
+ //ALL.add(new KeyPairGeneratorIdent("ECGOST3410-2012"));
+ // ECKCDSA? Botan provides.
+ ALL.add(new KeyPairGeneratorIdent("ECKCDSA"));
+ // ECGDSA? Botan provides.
+ ALL.add(new KeyPairGeneratorIdent("ECGDSA"));
+ }
+
+ public static KeyPairGeneratorIdent get(String ident) {
+ for (KeyPairGeneratorIdent kg : ALL) {
+ if (kg.getIdents().contains(ident)) {
+ return kg;
+ }
+ }
+ return null;
+ }
+
+ public static List<KeyPairGeneratorIdent> list() {
+ return Collections.unmodifiableList(ALL);
+ }
+
+ public KeyPairGeneratorIdent(String name, String... aliases) {
+ super(name, aliases);
+ }
+
+ public KeyPairGenerator getInstance(Provider provider) throws NoSuchAlgorithmException {
+ KeyPairGenerator instance = getInstance((algorithm, provider1) -> {
+ try {
+ return KeyPairGenerator.getInstance(algorithm, provider1);
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ }, provider);
+ instance.getProvider();
+ return instance;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java
new file mode 100644
index 0000000..c3913b7
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/SignatureIdent.java
@@ -0,0 +1,141 @@
+package cz.crcs.ectester.standalone.consts;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class SignatureIdent extends Ident {
+ private String hash;
+ private String sig;
+
+ private static final List<SignatureIdent> ALL = new LinkedList<>();
+
+ static {
+ //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html
+ // ECDSA
+ ALL.add(new SignatureIdent("ECDSA", "SHA1withECDSA", "ECDSAwithSHA1", "1.2.840.10045.4.1", "1.3.36.3.3.2.1"));
+ ALL.add(new SignatureIdent("NONEwithECDSA"));
+ ALL.add(new SignatureIdent("SHA224withECDSA", "SHA224/ECDSA", "1.2.840.10045.4.3.1"));
+ ALL.add(new SignatureIdent("SHA256withECDSA", "SHA256/ECDSA", "1.2.840.10045.4.3.2"));
+ ALL.add(new SignatureIdent("SHA384withECDSA", "SHA384/ECDSA", "1.2.840.10045.4.3.3"));
+ ALL.add(new SignatureIdent("SHA512withECDSA", "SHA512/ECDSA", "1.2.840.10045.4.3.4"));
+ ALL.add(new SignatureIdent("SHA3-224withECDSA", "SHA3-224/ECDSA", "2.16.840.1.101.3.4.3.9"));
+ ALL.add(new SignatureIdent("SHA3-256withECDSA", "SHA3-256/ECDSA", "2.16.840.1.101.3.4.3.10"));
+ ALL.add(new SignatureIdent("SHA3-384withECDSA", "SHA3-384/ECDSA", "2.16.840.1.101.3.4.3.11"));
+ ALL.add(new SignatureIdent("SHA3-512withECDSA", "SHA3-512/ECDSA", "2.16.840.1.101.3.4.3.12"));
+ ALL.add(new SignatureIdent("RIPEMD160withECDSA", "RIPEMD160/ECDSA", "1.3.36.3.3.2.2"));
+ // ECNR
+ ALL.add(new SignatureIdent("SHA1withECNR"));
+ ALL.add(new SignatureIdent("SHA224withECNR"));
+ ALL.add(new SignatureIdent("SHA256withECNR"));
+ ALL.add(new SignatureIdent("SHA512withECNR"));
+ // CVC-ECDSA
+ ALL.add(new SignatureIdent("SHA1withCVC-ECDSA", "SHA1/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.1"));
+ ALL.add(new SignatureIdent("SHA224withCVC-ECDSA", "SHA224/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.2"));
+ ALL.add(new SignatureIdent("SHA256withCVC-ECDSA", "SHA256/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.3"));
+ ALL.add(new SignatureIdent("SHA384withCVC-ECDSA", "SHA384/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.4"));
+ ALL.add(new SignatureIdent("SHA512withCVC-ECDSA", "SHA512/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.5"));
+ // PLAIN-ECDSA
+ ALL.add(new SignatureIdent("SHA1withPLAIN-ECDSA", "SHA1/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.1"));
+ ALL.add(new SignatureIdent("SHA224withPLAIN-ECDSA", "SHA224/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.2"));
+ ALL.add(new SignatureIdent("SHA256withPLAIN-ECDSA", "SHA256/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.3"));
+ ALL.add(new SignatureIdent("SHA384withPLAIN-ECDSA", "SHA384/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.4"));
+ ALL.add(new SignatureIdent("SHA512withPLAIN-ECDSA", "SHA512/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.5"));
+ ALL.add(new SignatureIdent("RIPEMD160withPLAIN-ECDSA", "RIPEMD160/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.6"));
+ // ECGOST
+ ALL.add(new SignatureIdent("ECGOST3410", "ECGOST-3410", "GOST-3410-2001"));
+ ALL.add(new SignatureIdent("GOST3411withECGOST3410", "GOST3411/ECGOST3410", "1.2.643.2.2.3"));
+ ALL.add(new SignatureIdent("ECGOST3410-2012-256", "GOST-3410-2012-256"));
+ ALL.add(new SignatureIdent("GOST3411-2012-256withECGOST3410-2012-256", "GOST3411-2012-256/ECGOST3410-2012-2560", "1.2.643.7.1.1.3.2"));
+ ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512"));
+ ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3"));
+ ALL.add(new SignatureIdent("SM3withSM2"));
+ // ECDDSA (rfc6979?)
+ ALL.add(new SignatureIdent("ECDDSA", "SHA1withECDDSA", "SHA1withDETECDSA", "DETECDSA", "ECDETDSA"));
+ ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA256withECDDSA", "SHA256withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA384withECDDSA", "SHA384withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA512withECDDSA", "SHA512withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-224withECDDSA", "SHA3-224withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-256withECDDSA", "SHA3-256withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-384withECDDSA", "SHA3-384withDETECDSA"));
+ ALL.add(new SignatureIdent("SHA3-512withECDDSA", "SHA3-512withDETECDSA"));
+ // ECKCDSA? Botan provides.
+ ALL.add(new SignatureIdent("ECKCDSA", "SHA1withECKCDSA", "1.2.410.200004.1.100.4.3"));
+ ALL.add(new SignatureIdent("NONEwithECKCDSA"));
+ ALL.add(new SignatureIdent("RIPEMD160withECKCDSA"));
+ ALL.add(new SignatureIdent("SHA224withECKCDSA", "1.2.410.200004.1.100.4.4"));
+ ALL.add(new SignatureIdent("SHA256withECKCDSA", "1.2.410.200004.1.100.4.5"));
+ ALL.add(new SignatureIdent("SHA384withECKCDSA"));
+ ALL.add(new SignatureIdent("SHA512withECKCDSA"));
+ // ECGDSA? Botan provides.
+ ALL.add(new SignatureIdent("ECGDSA", "SHA1withECGDSA", "1.3.36.3.3.2.5.4.2"));
+ ALL.add(new SignatureIdent("NONEwithECGDSA"));
+ ALL.add(new SignatureIdent("RIPEMD160withECGDSA", "1.3.36.3.3.2.5.4.1"));
+ ALL.add(new SignatureIdent("SHA224withECGDSA", "1.3.36.3.3.2.5.4.3"));
+ ALL.add(new SignatureIdent("SHA224withECGDSA", "1.3.36.3.3.2.5.4.4"));
+ ALL.add(new SignatureIdent("SHA384withECGDSA", "1.3.36.3.3.2.5.4.5"));
+ ALL.add(new SignatureIdent("SHA512withECGDSA", "1.3.36.3.3.2.5.4.6"));
+ }
+
+ public static SignatureIdent get(String ident) {
+ for (SignatureIdent sig : ALL) {
+ if (sig.getIdents().contains(ident)) {
+ return sig;
+ }
+ }
+ return null;
+ }
+
+ public static List<SignatureIdent> list() {
+ return Collections.unmodifiableList(ALL);
+ }
+
+ private SignatureIdent(String name, String... aliases) {
+ super(name, aliases);
+ if (name.contains("with")) {
+ int split = name.indexOf("with");
+ this.hash = name.substring(0, split);
+ this.sig = name.substring(split + 4);
+ } else {
+ for (String alias : aliases) {
+ if (alias.contains("with")) {
+ int split = alias.indexOf("with");
+ this.hash = alias.substring(0, split);
+ this.sig = alias.substring(split + 4);
+ break;
+ }
+ }
+ }
+ }
+
+ public Signature getInstance(Provider provider) throws NoSuchAlgorithmException {
+ Signature instance = getInstance((algorithm, provider1) -> {
+ try {
+ return Signature.getInstance(algorithm, provider1);
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ }, provider);
+ instance.getProvider();
+ return instance;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ public String getHashAlgo() {
+ return hash;
+ }
+
+ public String getSigType() {
+ return sig;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BoringsslLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BoringsslLib.java
new file mode 100644
index 0000000..60ca5d9
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BoringsslLib.java
@@ -0,0 +1,19 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class BoringsslLib extends NativeECLibrary {
+ public BoringsslLib() {
+ super("boringssl_provider", "lib_boringssl.so");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BotanLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BotanLib.java
new file mode 100644
index 0000000..cd28791
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BotanLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class BotanLib extends NativeECLibrary {
+
+ public BotanLib() {
+ super("botan_provider", "botan-2");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java
new file mode 100644
index 0000000..c6600f9
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java
@@ -0,0 +1,28 @@
+package cz.crcs.ectester.standalone.libs;
+
+import org.bouncycastle.jce.ECNamedCurveTable;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class BouncyCastleLib extends ProviderECLibrary {
+
+ public BouncyCastleLib() {
+ super(new BouncyCastleProvider());
+ }
+
+ @Override
+ public Set<String> getCurves() {
+ Set<String> result = new TreeSet<>();
+ Enumeration names = ECNamedCurveTable.getNames();
+ while (names.hasMoreElements()) {
+ result.add((String) names.nextElement());
+ }
+ return result;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/CryptoppLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/CryptoppLib.java
new file mode 100644
index 0000000..5112d7d
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/CryptoppLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class CryptoppLib extends NativeECLibrary {
+
+ public CryptoppLib() {
+ super("cryptopp_provider", "cryptopp");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ECLibrary.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ECLibrary.java
new file mode 100644
index 0000000..0f81978
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ECLibrary.java
@@ -0,0 +1,26 @@
+package cz.crcs.ectester.standalone.libs;
+
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public interface ECLibrary {
+ boolean initialize();
+
+ boolean isInitialized();
+
+ Set<String> getCurves();
+
+ Set<KeyAgreementIdent> getKAs();
+
+ Set<SignatureIdent> getSigs();
+
+ Set<KeyPairGeneratorIdent> getKPGs();
+
+ String name();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/GcryptLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/GcryptLib.java
new file mode 100644
index 0000000..a0a7fc8
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/GcryptLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class GcryptLib extends NativeECLibrary {
+
+ public GcryptLib() {
+ super("gcrypt_provider", "gcrypt", "gpg-error");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/IppcpLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/IppcpLib.java
new file mode 100644
index 0000000..0dec0a2
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/IppcpLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class IppcpLib extends NativeECLibrary {
+
+ public IppcpLib() {
+ super("ippcp_provider", "lib_ippcp.so");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/LibresslLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/LibresslLib.java
new file mode 100644
index 0000000..cee4e4d
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/LibresslLib.java
@@ -0,0 +1,19 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Matěj Grabovský matej@mgrabovsky.net
+ */
+public class LibresslLib extends NativeECLibrary {
+ public LibresslLib() {
+ super("libressl_provider", "lib_libressl.so");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MatrixsslLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MatrixsslLib.java
new file mode 100644
index 0000000..fcc13ea
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MatrixsslLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class MatrixsslLib extends NativeECLibrary {
+
+ public MatrixsslLib() {
+ super("matrixssl_provider");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MbedTLSLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MbedTLSLib.java
new file mode 100644
index 0000000..ace10d7
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MbedTLSLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class MbedTLSLib extends NativeECLibrary {
+
+ public MbedTLSLib() {
+ super("mbedtls_provider", "mbedcrypto");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MscngLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MscngLib.java
new file mode 100644
index 0000000..527a65b
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/MscngLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class MscngLib extends NativeECLibrary {
+
+ public MscngLib() {
+ super("mscng_provider", "bcrypt");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
new file mode 100644
index 0000000..2f469aa
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
@@ -0,0 +1,93 @@
+package cz.crcs.ectester.standalone.libs;
+
+import cz.crcs.ectester.common.util.FileUtil;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeECLibrary extends ProviderECLibrary {
+ private String resource;
+ private String[] requriements;
+
+
+ public NativeECLibrary(String resource, String... requirements) {
+ this.resource = resource;
+ this.requriements = requirements;
+ }
+
+ @Override
+ public boolean initialize() {
+ try {
+ /* Determine what OS are we running on and use appropriate suffix and path. */
+ String suffix = FileUtil.getLibSuffix();
+
+ /* Resolve and create the ECTester directories in appData. */
+ Path libDir = FileUtil.getLibDir();
+ Path libReqDir = FileUtil.getRequirementsDir();
+ Path libPath = libDir.resolve(resource + "." + suffix);
+
+ /* Write the shim. */
+ boolean found = FileUtil.writeNewer(ECTesterStandalone.LIB_RESOURCE_DIR + resource + "." + suffix, libPath);
+ if (!found) {
+ //System.err.printf("Resource %s not found.\n", resource);
+ return false;
+ }
+
+ /* Load the requirements, if they are bundled, write them in and load them. */
+ try {
+ for (String requirement : requriements) {
+ if (requirement.endsWith(suffix)) {
+ /* The requirement is bundled, write it */
+ Path reqPath = libReqDir.resolve(requirement);
+ found = FileUtil.writeNewer(ECTesterStandalone.LIB_RESOURCE_DIR + requirement, reqPath);
+ if (!found) {
+ //System.err.printf("Requirement %s not found for %s.\n", requirement, resource);
+ return false;
+ }
+ System.load(reqPath.toString());
+ } else {
+ System.loadLibrary(requirement);
+ }
+ }
+ } catch (UnsatisfiedLinkError ule) {
+ System.err.println(resource);
+ ule.printStackTrace();
+ return false;
+ }
+
+ System.load(libPath.toString());
+
+ provider = createProvider();
+ return super.initialize();
+ } catch (IOException | UnsatisfiedLinkError ignored) {
+ System.err.println(resource);
+ ignored.printStackTrace();
+ }
+ return false;
+ }
+
+
+ @Override
+ public native Set<String> getNativeTimingSupport();
+
+ @Override
+ public native boolean setNativeTimingType(String type);
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native String getNativeTimingUnit();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ abstract Provider createProvider();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java
new file mode 100644
index 0000000..00e3b39
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NettleLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Michal Cech 445431@mail.muni.cz
+ */
+public class NettleLib extends NativeECLibrary {
+
+ public NettleLib() {
+ super("nettle_provider", "nettle","hogweed", "gmp");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java
new file mode 100644
index 0000000..e558336
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/OpensslLib.java
@@ -0,0 +1,19 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class OpensslLib extends NativeECLibrary {
+ public OpensslLib() {
+ super("openssl_provider", "crypto");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
new file mode 100644
index 0000000..dd8e49c
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
@@ -0,0 +1,113 @@
+package cz.crcs.ectester.standalone.libs;
+
+import cz.crcs.ectester.standalone.consts.Ident;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class ProviderECLibrary implements ECLibrary {
+ Provider provider;
+ private boolean initialized = false;
+
+ public ProviderECLibrary() {
+
+ }
+
+ public ProviderECLibrary(Provider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public boolean initialize() {
+ try {
+ int result = Security.addProvider(provider);
+ if (result == -1) {
+ provider = Security.getProvider(provider.getName());
+ }
+ initialized = true;
+ } catch (NullPointerException | SecurityException ignored) {
+ initialized = false;
+ }
+ return initialized;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return initialized;
+ }
+
+ private <T extends Ident> Set<T> getIdents(String type, Function<String, T> getter) {
+ Set<T> results = new HashSet<>();
+ if (!initialized) {
+ return results;
+ }
+
+ for (Provider.Service service : provider.getServices()) {
+ if (service.getType().equals(type)) {
+ T id = getter.apply(service.getAlgorithm());
+ if (id != null) {
+ results.add(id);
+ }
+ }
+ }
+ return results;
+ }
+
+ public Set<String> getNativeTimingSupport() {
+ return new HashSet<>();
+ }
+
+ public boolean setNativeTimingType(String type) {
+ return false;
+ }
+
+ public long getNativeTimingResolution() {
+ return 0;
+ }
+
+ public String getNativeTimingUnit() {
+ return null;
+ }
+
+ public long getLastNativeTiming() {
+ return 0;
+ }
+
+ @Override
+ public Set<KeyAgreementIdent> getKAs() {
+ return getIdents("KeyAgreement", KeyAgreementIdent::get);
+ }
+
+ @Override
+ public Set<SignatureIdent> getSigs() {
+ return getIdents("Signature", SignatureIdent::get);
+ }
+
+ @Override
+ public Set<KeyPairGeneratorIdent> getKPGs() {
+ return getIdents("KeyPairGenerator", KeyPairGeneratorIdent::get);
+ }
+
+ @Override
+ public String name() {
+ return provider.getInfo();
+ }
+
+ public Provider getProvider() {
+ return provider;
+ }
+
+ @Override
+ public String toString() {
+ return name();
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/SunECLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/SunECLib.java
new file mode 100644
index 0000000..3aec842
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/SunECLib.java
@@ -0,0 +1,28 @@
+package cz.crcs.ectester.standalone.libs;
+
+import sun.security.ec.SunEC;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class SunECLib extends ProviderECLibrary {
+
+ public SunECLib() {
+ super(new SunEC());
+ }
+
+ @Override
+ public Set<String> getCurves() {
+ String curves = provider.get("AlgorithmParameters.EC SupportedCurves").toString();
+ String[] split = curves.split("\\|");
+ Set<String> result = new TreeSet<>();
+ for (String curve : split) {
+ String body = curve.split(",")[0].substring(1);
+ result.add(body);
+ }
+ return result;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/TomcryptLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/TomcryptLib.java
new file mode 100644
index 0000000..78db00e
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/TomcryptLib.java
@@ -0,0 +1,20 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TomcryptLib extends NativeECLibrary {
+
+ public TomcryptLib() {
+ super("tomcrypt_provider", "tommath", "tomcrypt");
+ }
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
new file mode 100644
index 0000000..b58eb91
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
@@ -0,0 +1,18 @@
+package cz.crcs.ectester.standalone.libs;
+
+import com.wolfssl.provider.jce.WolfCryptProvider;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class WolfCryptLib extends ProviderECLibrary {
+
+ public WolfCryptLib() {
+ super(new WolfCryptProvider());
+ }
+
+ @Override
+ public Set<String> getCurves() {
+ return new HashSet<>();
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
new file mode 100644
index 0000000..81bd387
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -0,0 +1,184 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ByteUtil;
+import org.bouncycastle.util.Arrays;
+
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public abstract class NativeECPrivateKey implements ECPrivateKey {
+ private String algorithm;
+ private String format;
+ ECParameterSpec params;
+
+ public NativeECPrivateKey(String algorithm, String format, ECParameterSpec params) {
+ this.algorithm = algorithm;
+ this.format = format;
+ this.params = params;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+
+ public abstract byte[] getData();
+
+ @SuppressWarnings("serial")
+ private static class Raw extends NativeECPrivateKey {
+ byte[] keyData;
+
+ public Raw(byte[] keyData, ECParameterSpec params) {
+ super("EC", "raw", params);
+ this.keyData = Arrays.clone(keyData);
+ }
+
+ @Override
+ public BigInteger getS() {
+ return new BigInteger(1, keyData);
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return Arrays.clone(keyData);
+ }
+
+ public byte[] getData() {
+ return getEncoded();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class TomCrypt extends Raw {
+ public TomCrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Botan extends Raw {
+ public Botan(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Cryptopp extends Raw {
+ public Cryptopp(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Openssl extends Raw {
+ public Openssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Boringssl extends Raw {
+ public Boringssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Gcrypt extends Raw {
+ public Gcrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class MbedTLS extends Raw {
+ public MbedTLS(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Ippcp extends Raw {
+ public Ippcp(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Matrixssl extends Raw {
+ public Matrixssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Libressl extends Raw {
+ public Libressl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Mscng extends Raw {
+ // 0 -> implicit (meta = curveName UTF16, header = full);
+ // 1 -> explicit (meta = null, header = full);
+ // 2 -> nist (meta = null, header = full)
+ private int flag;
+ private byte[] meta = null;
+ private byte[] header;
+ private byte[] x;
+ private byte[] y;
+
+ public Mscng(int flag, byte[] meta, byte[] header, byte[] x, byte[] y, byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ this.flag = flag;
+ this.meta = Arrays.clone(meta);
+ this.header = Arrays.clone(header);
+ this.x = Arrays.clone(x);
+ this.y = Arrays.clone(y);
+ }
+
+ public int getFlag() {
+ return flag;
+ }
+
+ public byte[] getMeta() {
+ return Arrays.clone(meta);
+ }
+
+ public byte[] getHeader() {
+ return Arrays.clone(header);
+ }
+
+ public byte[] getBlob() {
+ return ByteUtil.concatenate(header, x, y, keyData);
+ }
+
+ @Override
+ public byte[] getData() {
+ return getBlob();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Nettle extends Raw {
+ public Nettle(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
new file mode 100644
index 0000000..7a8de83
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
@@ -0,0 +1,185 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.ECUtil;
+import org.bouncycastle.util.Arrays;
+
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public abstract class NativeECPublicKey implements ECPublicKey {
+ private String algorithm;
+ private String format;
+ ECParameterSpec params;
+
+ public NativeECPublicKey(String algorithm, String format, ECParameterSpec params) {
+ this.algorithm = algorithm;
+ this.format = format;
+ this.params = params;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return params;
+ }
+
+ public abstract byte[] getData();
+
+ @SuppressWarnings("serial")
+ private static class ANSIX962 extends NativeECPublicKey {
+ byte[] keyData;
+
+ public ANSIX962(byte[] keyData, ECParameterSpec params) {
+ super("EC", "ANSI X9.62", params);
+ this.keyData = Arrays.clone(keyData);
+ }
+
+ @Override
+ public ECPoint getW() {
+ return ECUtil.fromX962(keyData, params.getCurve());
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return Arrays.clone(keyData);
+ }
+
+ public byte[] getData() {
+ return ECUtil.toX962Uncompressed(getW(), params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class TomCrypt extends ANSIX962 {
+ public TomCrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Botan extends ANSIX962 {
+ public Botan(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Cryptopp extends ANSIX962 {
+ public Cryptopp(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Openssl extends ANSIX962 {
+ public Openssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Boringssl extends ANSIX962 {
+ public Boringssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Gcrypt extends ANSIX962 {
+ public Gcrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class MbedTLS extends ANSIX962 {
+ public MbedTLS(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Ippcp extends ANSIX962 {
+ public Ippcp(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Matrixssl extends ANSIX962 {
+ public Matrixssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Libressl extends ANSIX962 {
+ public Libressl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Mscng extends ANSIX962 {
+ // 0 -> implicit (meta = curveName UTF16, header = full);
+ // 1 -> explicit (meta = null, header = full);
+ // 2 -> nist (meta = null, header = full)
+ private int flag;
+ private byte[] meta = null;
+ private byte[] header;
+ private byte[] x;
+ private byte[] y;
+
+ public Mscng(int flag, byte[] meta, byte[] header, byte[] x, byte[] y, ECParameterSpec params) {
+ super(ByteUtil.concatenate(new byte[]{0x04}, x, y), params);
+ this.flag = flag;
+ this.meta = Arrays.clone(meta);
+ this.header = Arrays.clone(header);
+ this.x = Arrays.clone(x);
+ this.y = Arrays.clone(y);
+ }
+
+ public int getFlag() {
+ return flag;
+ }
+
+ public byte[] getMeta() {
+ return Arrays.clone(meta);
+ }
+
+ public byte[] getHeader() {
+ return Arrays.clone(header);
+ }
+
+ public byte[] getBlob() {
+ return ByteUtil.concatenate(header, x, y);
+ }
+
+ @Override
+ public byte[] getData() {
+ return getBlob();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class Nettle extends ANSIX962 {
+ public Nettle(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
new file mode 100644
index 0000000..1e68f78
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -0,0 +1,449 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
+ ECPrivateKey privateKey;
+ ECPublicKey publicKey;
+ AlgorithmParameterSpec params;
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
+ if (!(key instanceof ECPrivateKey)) {
+ throw new InvalidKeyException
+ ("Key must be instance of ECPrivateKey");
+ }
+ privateKey = (ECPrivateKey) key;
+ this.params = privateKey.getParams();
+ }
+
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException {
+ if (privateKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (publicKey != null) {
+ throw new IllegalStateException("Phase already executed");
+ }
+ if (!lastPhase) {
+ throw new IllegalStateException
+ ("Only two party agreement supported, lastPhase must be true");
+ }
+ if (!(key instanceof ECPublicKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPublicKey");
+ }
+ publicKey = (ECPublicKey) key;
+ return null;
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException {
+ byte[] secret = engineGenerateSecret();
+ if (sharedSecret.length < offset + secret.length) {
+ throw new ShortBufferException();
+ }
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+ return secret.length;
+ }
+
+ private abstract static class SimpleKeyAgreementSpi extends NativeKeyAgreementSpi {
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (!(params instanceof ECParameterSpec)) {
+ throw new InvalidAlgorithmParameterException(params.toString());
+ }
+ engineInit(key, random);
+ this.params = params;
+ }
+
+ private byte[] getPubkey() {
+ if (publicKey instanceof NativeECPublicKey) {
+ return ((NativeECPublicKey) publicKey).getData();
+ } else {
+ return ECUtil.toX962Uncompressed(publicKey.getW(), ((ECParameterSpec) params));
+ }
+ }
+
+ private byte[] getPrivkey() {
+ if (privateKey instanceof NativeECPrivateKey) {
+ return ((NativeECPrivateKey) privateKey).getData();
+ } else {
+ return ECUtil.toByteArray(privateKey.getS(), ((ECParameterSpec) params).getOrder().bitLength());
+ }
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ return generateSecret(getPubkey(), getPrivkey(), (ECParameterSpec) params);
+ }
+
+ abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException {
+ if (algorithm == null) {
+ throw new NoSuchAlgorithmException("Algorithm must not be null");
+ }
+ return generateSecret(getPubkey(), getPrivkey(), (ECParameterSpec) params, algorithm);
+ }
+
+ abstract SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ private abstract static class ExtendedKeyAgreementSpi extends NativeKeyAgreementSpi {
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ if (!(params instanceof ECParameterSpec || params instanceof ECGenParameterSpec)) {
+ throw new InvalidAlgorithmParameterException();
+ }
+ engineInit(key, random);
+ this.params = params;
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ return generateSecret(publicKey, privateKey, params);
+ }
+
+ abstract byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params);
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException {
+ if (algorithm == null) {
+ throw new NoSuchAlgorithmException("Algorithm must not be null");
+ }
+ return generateSecret(publicKey, privateKey, params, algorithm);
+ }
+
+ abstract SecretKey generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params, String algorithm);
+ }
+
+
+ public static class TomCrypt extends SimpleKeyAgreementSpi {
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public abstract static class Botan extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Botan(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class BotanECDH extends Botan {
+ public BotanECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class BotanECDHwithSHA1KDF extends Botan {
+ public BotanECDHwithSHA1KDF() {
+ super("ECDHwithSHA1KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA224KDF extends Botan {
+ public BotanECDHwithSHA224KDF() {
+ super("ECDHwithSHA224KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA256KDF extends Botan {
+ public BotanECDHwithSHA256KDF() {
+ super("ECDHwithSHA256KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA384KDF extends Botan {
+ public BotanECDHwithSHA384KDF() {
+ super("ECDHwithSHA384KDF");
+ }
+ }
+
+ public static class BotanECDHwithSHA512KDF extends Botan {
+ public BotanECDHwithSHA512KDF() {
+ super("ECDHwithSHA512KDF");
+ }
+ }
+
+ public abstract static class Cryptopp extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Cryptopp(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class CryptoppECDH extends Cryptopp {
+ public CryptoppECDH() {
+ super("ECDH");
+ }
+ }
+
+ public abstract static class Openssl extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Openssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class OpensslECDH extends Openssl {
+ public OpensslECDH() {
+ super("ECDH");
+ }
+ }
+
+ public abstract static class Boringssl extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Boringssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class BoringsslECDH extends Boringssl {
+ public BoringsslECDH() {
+ super("ECDH");
+ }
+ }
+
+ public abstract static class Gcrypt extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Gcrypt(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class GcryptECDH extends Gcrypt {
+ public GcryptECDH() {
+ super("ECDH");
+ }
+ }
+
+
+ public abstract static class Mscng extends ExtendedKeyAgreementSpi {
+ private String type;
+
+ public Mscng(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params, String algorithm);
+ }
+
+ public static class MscngECDHwithSHA1KDF extends Mscng {
+ public MscngECDHwithSHA1KDF() {
+ super("ECDHwithSHA1KDF(CNG)");
+ }
+ }
+
+ public static class MscngECDHwithSHA256KDF extends Mscng {
+ public MscngECDHwithSHA256KDF() {
+ super("ECDHwithSHA256KDF(CNG)");
+ }
+ }
+
+ public static class MscngECDHwithSHA384KDF extends Mscng {
+ public MscngECDHwithSHA384KDF() {
+ super("ECDHwithSHA384KDF(CNG)");
+ }
+ }
+
+ public static class MscngECDHwithSHA512KDF extends Mscng {
+ public MscngECDHwithSHA512KDF() {
+ super("ECDHwithSHA512KDF(CNG)");
+ }
+ }
+
+ public abstract static class MbedTLS extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public MbedTLS(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class MbedTLSECDH extends MbedTLS {
+ public MbedTLSECDH() {
+ super("ECDH");
+ }
+ }
+
+ public abstract static class Ippcp extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Ippcp(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class IppcpECDH extends Ippcp {
+ public IppcpECDH() {
+ super("ECDH");
+ }
+ }
+
+ public abstract static class Matrixssl extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Matrixssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class MatrixsslECDH extends Matrixssl {
+ public MatrixsslECDH() {
+ super("ECDH");
+ }
+ }
+
+ public abstract static class Libressl extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Libressl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public abstract static class Nettle extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Nettle(String type) {
+ this.type = type;
+ }
+
+ @Override
+ byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params) {
+ try {
+ AlgorithmParameters tmp = AlgorithmParameters.getInstance("EC");
+ tmp.init(params);
+ ECGenParameterSpec spec = tmp.getParameterSpec(ECGenParameterSpec.class);
+ switch (spec.getName()) {
+ case "1.2.840.10045.3.1.7":
+ spec = new ECGenParameterSpec("secp256r1");
+ break;
+ case "1.2.840.10045.3.1.1":
+ spec = new ECGenParameterSpec("secp192r1");
+ break;
+ case "1.3.132.0.33":
+ spec = new ECGenParameterSpec("secp224r1");
+ break;
+ case "1.3.132.0.34":
+ spec = new ECGenParameterSpec("secp384r1");
+ break;
+ case "1.3.132.0.35":
+ spec = new ECGenParameterSpec("secp521r1");
+ break;
+ default:
+ return null;
+
+ }
+ return generateSecret(pubkey, privkey, spec);
+
+ } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECGenParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class NettleECDH extends Nettle {
+ public NettleECDH() {
+ super("ECDH");
+ }
+ }
+ public static class LibresslECDH extends Libressl {
+ public LibresslECDH() {
+ super("ECDH");
+ }
+ }
+
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
new file mode 100644
index 0000000..636f423
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
@@ -0,0 +1,367 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.data.EC_Store;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.AlgorithmParameters;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
+ private int keysize;
+ private SecureRandom random;
+ private AlgorithmParameterSpec params;
+ private boolean useKeysize;
+ private boolean useParams;
+
+ public static final int DEFAULT_KEYSIZE = 256;
+
+ @Override
+ public void initialize(int keysize, SecureRandom random) {
+ if (!keysizeSupported(keysize)) {
+ throw new InvalidParameterException("Keysize " + keysize + " not supported.");
+ }
+ this.keysize = keysize;
+ this.random = random;
+ this.useKeysize = true;
+ this.useParams = false;
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException {
+ if (!paramsSupported(params)) {
+ throw new InvalidAlgorithmParameterException("Not supported.");
+ }
+ this.params = params;
+ this.random = random;
+ this.useParams = true;
+ this.useKeysize = false;
+ }
+
+ @Override
+ public KeyPair generateKeyPair() {
+ if (!useKeysize && !useParams) {
+ if (keysizeSupported(DEFAULT_KEYSIZE)) {
+ initialize(DEFAULT_KEYSIZE, new SecureRandom());
+ }
+ }
+
+ if (useKeysize) {
+ return generate(keysize, random);
+ } else if (useParams) {
+ return generate(params, random);
+ } else {
+ throw new IllegalStateException("Uninitialized KeyPair.");
+ }
+ }
+
+ abstract boolean keysizeSupported(int keysize);
+
+ abstract boolean paramsSupported(AlgorithmParameterSpec params);
+
+ abstract KeyPair generate(int keysize, SecureRandom random);
+
+ abstract KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+
+
+ public static class TomCrypt extends NativeKeyPairGeneratorSpi {
+
+ public TomCrypt() {
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static abstract class Botan extends NativeKeyPairGeneratorSpi {
+ private String type;
+
+ public Botan(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class BotanECDH extends Botan {
+
+ public BotanECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class BotanECDSA extends Botan {
+
+ public BotanECDSA() {
+ super("ECDSA");
+ }
+ }
+
+ public static class BotanECKCDSA extends Botan {
+
+ public BotanECKCDSA() {
+ super("ECKCDSA");
+ }
+ }
+
+ public static class BotanECGDSA extends Botan {
+
+ public BotanECGDSA() {
+ super("ECGDSA");
+ }
+ }
+
+ public static abstract class Cryptopp extends NativeKeyPairGeneratorSpi {
+ private String type;
+
+ public Cryptopp(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class CryptoppECDH extends Cryptopp {
+
+ public CryptoppECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class CryptoppECDSA extends Cryptopp {
+
+ public CryptoppECDSA() {
+ super("ECDSA");
+ }
+ }
+
+ public static class Openssl extends NativeKeyPairGeneratorSpi {
+ public Openssl() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class Boringssl extends NativeKeyPairGeneratorSpi {
+ public Boringssl() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class Gcrypt extends NativeKeyPairGeneratorSpi {
+
+ public Gcrypt() {
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static abstract class Mscng extends NativeKeyPairGeneratorSpi {
+ private String type;
+
+ public Mscng(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class MscngECDH extends Mscng {
+
+ public MscngECDH() {
+ super("ECDH");
+ }
+ }
+
+ public static class MscngECDSA extends Mscng {
+
+ public MscngECDSA() {
+ super("ECDSA");
+ }
+ }
+
+ public static class MbedTLS extends NativeKeyPairGeneratorSpi {
+
+ public MbedTLS() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class Ippcp extends NativeKeyPairGeneratorSpi {
+
+ public Ippcp() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class Matrixssl extends NativeKeyPairGeneratorSpi {
+
+ public Matrixssl() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class Libressl extends NativeKeyPairGeneratorSpi {
+
+ public Libressl() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class Nettle extends NativeKeyPairGeneratorSpi {
+ public Nettle() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ KeyPair generate(AlgorithmParameterSpec params, SecureRandom random) {
+ if (params instanceof ECGenParameterSpec) {
+ String curveName = ((ECGenParameterSpec) params).getName();
+ if (curveName.contains("secp")) {
+ curveName = "secg/" + curveName;
+ }
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ ECParameterSpec spec = curve.toSpec();
+ return generate(params, random, spec);
+ }
+ return null;
+ }
+
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random, AlgorithmParameterSpec spec);
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
new file mode 100644
index 0000000..e036937
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
@@ -0,0 +1,159 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+@SuppressWarnings("serial")
+public abstract class NativeProvider extends Provider {
+
+ public NativeProvider(String name, double version, String info) {
+ super(name, version, info);
+
+ if (System.getSecurityManager() == null) {
+ setup();
+ } else {
+ AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
+ setup();
+ return null;
+ });
+ }
+ }
+
+ abstract void setup();
+
+ @SuppressWarnings("serial")
+ public static class TomCrypt extends NativeProvider {
+
+ public TomCrypt(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Botan extends NativeProvider {
+
+ public Botan(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Cryptopp extends NativeProvider {
+
+ public Cryptopp(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Openssl extends NativeProvider {
+
+ public Openssl(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Boringssl extends NativeProvider {
+
+ public Boringssl(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Gcrypt extends NativeProvider {
+
+ public Gcrypt(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Mscng extends NativeProvider {
+
+ public Mscng(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class MbedTLS extends NativeProvider {
+
+ public MbedTLS(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Ippcp extends NativeProvider {
+
+ public Ippcp(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Matrixssl extends NativeProvider {
+
+ public Matrixssl(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Libressl extends NativeProvider {
+
+ public Libressl(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ @SuppressWarnings("serial")
+ public static class Nettle extends NativeProvider {
+
+ public Nettle(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
new file mode 100644
index 0000000..d6e814c
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
@@ -0,0 +1,657 @@
+package cz.crcs.ectester.standalone.libs.jni;
+
+import cz.crcs.ectester.common.util.ECUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class NativeSignatureSpi extends SignatureSpi {
+ ECPublicKey verifyKey;
+ ECPrivateKey signKey;
+ ECParameterSpec params;
+
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ if (!(publicKey instanceof ECPublicKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPublicKey");
+ }
+ verifyKey = (ECPublicKey) publicKey;
+ params = verifyKey.getParams();
+ buffer.reset();
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ if (!(privateKey instanceof ECPrivateKey)) {
+ throw new InvalidKeyException
+ ("Key must be an instance of ECPrivateKey");
+ }
+ signKey = (ECPrivateKey) privateKey;
+ params = signKey.getParams();
+ buffer.reset();
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ buffer.write(b);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+ buffer.write(b, off, len);
+ }
+
+
+ @Override
+ @Deprecated
+ protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
+ throw new UnsupportedOperationException("setParameter() not supported");
+ }
+
+ @Override
+ @Deprecated
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ throw new UnsupportedOperationException("getParameter() not supported");
+ }
+
+ private abstract static class SimpleSignatureSpi extends NativeSignatureSpi {
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ byte[] privkey;
+ if (signKey instanceof NativeECPrivateKey) {
+ privkey = ((NativeECPrivateKey) signKey).getData();
+ } else {
+ privkey = ECUtil.toByteArray(signKey.getS(), params.getOrder().bitLength());
+ }
+ return sign(buffer.toByteArray(), privkey, params);
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ byte[] pubkey;
+ if (verifyKey instanceof NativeECPublicKey) {
+ pubkey = ((NativeECPublicKey) verifyKey).getData();
+ } else {
+ pubkey = ECUtil.toX962Uncompressed(verifyKey.getW(), params);
+ }
+ return verify(sigBytes, buffer.toByteArray(), pubkey, params);
+ }
+
+ abstract byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ abstract boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ private abstract static class ExtendedSignatureSpi extends NativeSignatureSpi {
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ return sign(buffer.toByteArray(), signKey, params);
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ return verify(sigBytes, buffer.toByteArray(), verifyKey, params);
+ }
+
+ abstract byte[] sign(byte[] data, ECPrivateKey privkey, ECParameterSpec params);
+
+ abstract boolean verify(byte[] signature, byte[] data, ECPublicKey pubkey, ECParameterSpec params);
+ }
+
+ public static class TomCryptRaw extends SimpleSignatureSpi {
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public abstract static class Botan extends SimpleSignatureSpi {
+ private String type;
+
+ public Botan(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class BotanECDSAwithNONE extends Botan {
+
+ public BotanECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA1 extends Botan {
+
+ public BotanECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA224 extends Botan {
+
+ public BotanECDSAwithSHA224() {
+ super("SHA224withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA256 extends Botan {
+
+ public BotanECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA384 extends Botan {
+
+ public BotanECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class BotanECDSAwithSHA512 extends Botan {
+
+ public BotanECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithNONE extends Botan {
+
+ public BotanECKCDSAwithNONE() {
+ super("NONEwithECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA1 extends Botan {
+
+ public BotanECKCDSAwithSHA1() {
+ super("SHA1withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA224 extends Botan {
+
+ public BotanECKCDSAwithSHA224() {
+ super("SHA224withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA256 extends Botan {
+
+ public BotanECKCDSAwithSHA256() {
+ super("SHA256withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA384 extends Botan {
+
+ public BotanECKCDSAwithSHA384() {
+ super("SHA384withECKCDSA");
+ }
+ }
+
+ public static class BotanECKCDSAwithSHA512 extends Botan {
+
+ public BotanECKCDSAwithSHA512() {
+ super("SHA512withECKCDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithNONE extends Botan {
+
+ public BotanECGDSAwithNONE() {
+ super("NONEwithECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA1 extends Botan {
+
+ public BotanECGDSAwithSHA1() {
+ super("SHA1withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA224 extends Botan {
+
+ public BotanECGDSAwithSHA224() {
+ super("SHA224withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA256 extends Botan {
+
+ public BotanECGDSAwithSHA256() {
+ super("SHA256withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA384 extends Botan {
+
+ public BotanECGDSAwithSHA384() {
+ super("SHA384withECGDSA");
+ }
+ }
+
+ public static class BotanECGDSAwithSHA512 extends Botan {
+
+ public BotanECGDSAwithSHA512() {
+ super("SHA512withECGDSA");
+ }
+ }
+
+ public abstract static class Cryptopp extends SimpleSignatureSpi {
+ private String type;
+
+ public Cryptopp(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class CryptoppECDSAwithSHA1 extends Cryptopp {
+
+ public CryptoppECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class CryptoppECDSAwithSHA224 extends Cryptopp {
+
+ public CryptoppECDSAwithSHA224() {
+ super("SHA224withECDSA");
+ }
+ }
+
+ public static class CryptoppECDSAwithSHA256 extends Cryptopp {
+
+ public CryptoppECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class CryptoppECDSAwithSHA384 extends Cryptopp {
+
+ public CryptoppECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class CryptoppECDSAwithSHA512 extends Cryptopp {
+
+ public CryptoppECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public abstract static class Openssl extends SimpleSignatureSpi {
+ private String type;
+
+ public Openssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class OpensslECDSAwithNONE extends Openssl {
+
+ public OpensslECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public abstract static class Boringssl extends SimpleSignatureSpi {
+ private String type;
+
+ public Boringssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class BoringsslECDSAwithNONE extends Boringssl {
+
+ public BoringsslECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public abstract static class Gcrypt extends SimpleSignatureSpi {
+ private String type;
+
+ public Gcrypt(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class GcryptECDSAwithNONE extends Gcrypt {
+
+ public GcryptECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA1 extends Gcrypt {
+
+ public GcryptECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA224 extends Gcrypt {
+
+ public GcryptECDSAwithSHA224() {
+ super("SHA224withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA256 extends Gcrypt {
+
+ public GcryptECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA384 extends Gcrypt {
+
+ public GcryptECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA512 extends Gcrypt {
+
+ public GcryptECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA1 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA1() {
+ super("SHA1withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA224 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA224() {
+ super("SHA224withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA256 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA256() {
+ super("SHA256withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA384 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA384() {
+ super("SHA384withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA512 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA512() {
+ super("SHA512withECDDSA");
+ }
+ }
+
+ public abstract static class MbedTLS extends SimpleSignatureSpi {
+ private String type;
+
+ public MbedTLS(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class MbedTLSECDSAwithNONE extends MbedTLS {
+
+ public MbedTLSECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public abstract static class Ippcp extends SimpleSignatureSpi {
+ private String type;
+
+ public Ippcp(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class IppcpECDSAwithNONE extends Ippcp {
+
+ public IppcpECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public abstract static class Libressl extends SimpleSignatureSpi {
+ private String type;
+
+ public Libressl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class LibresslECDSAwithNONE extends Libressl {
+
+ public LibresslECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public abstract static class Matrixssl extends SimpleSignatureSpi {
+ private String type;
+
+ public Matrixssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class MatrixsslECDSAwithNONE extends Matrixssl {
+
+ public MatrixsslECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public abstract static class Mscng extends ExtendedSignatureSpi {
+ private String type;
+
+ public Mscng(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, ECPrivateKey privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, ECPublicKey pubkey, ECParameterSpec params);
+ }
+
+ public static class MscngECDSAwithSHA1 extends Mscng {
+
+ public MscngECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class MscngECDSAwithSHA256 extends Mscng {
+
+ public MscngECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class MscngECDSAwithSHA384 extends Mscng {
+
+ public MscngECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class MscngECDSAwithSHA512 extends Mscng {
+
+ public MscngECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public abstract static class Nettle extends SimpleSignatureSpi {
+ private String type;
+
+ public Nettle(String type) {
+ this.type = type;
+ }
+
+ @Override
+ byte[] sign(byte[] data, byte[] privKey, ECParameterSpec params) {
+ try {
+ AlgorithmParameters tmp = AlgorithmParameters.getInstance("EC");
+ tmp.init(params);
+ ECGenParameterSpec spec = tmp.getParameterSpec(ECGenParameterSpec.class);
+ switch (spec.getName()) {
+ case "1.2.840.10045.3.1.7":
+ spec = new ECGenParameterSpec("secp256r1");
+ break;
+ case "1.2.840.10045.3.1.1":
+ spec = new ECGenParameterSpec("secp192r1");
+ break;
+ case "1.3.132.0.33":
+ spec = new ECGenParameterSpec("secp224r1");
+ break;
+ case "1.3.132.0.34":
+ spec = new ECGenParameterSpec("secp384r1");
+ break;
+ case "1.3.132.0.35":
+ spec = new ECGenParameterSpec("secp521r1");
+ break;
+ default:
+ return null;
+
+ }
+ return sign(data, privKey, spec);
+
+ } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ native byte[] sign(byte[] data, byte[] privKey, ECGenParameterSpec params);
+
+ @Override
+ boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params) {
+ try {
+ AlgorithmParameters tmp = AlgorithmParameters.getInstance("EC");
+ tmp.init(params);
+ ECGenParameterSpec spec = tmp.getParameterSpec(ECGenParameterSpec.class);
+ switch (spec.getName()) {
+ case "1.2.840.10045.3.1.7":
+ spec = new ECGenParameterSpec("secp256r1");
+ break;
+ case "1.2.840.10045.3.1.1":
+ spec = new ECGenParameterSpec("secp192r1");
+ break;
+ case "1.3.132.0.33":
+ spec = new ECGenParameterSpec("secp224r1");
+ break;
+ case "1.3.132.0.34":
+ spec = new ECGenParameterSpec("secp384r1");
+ break;
+ case "1.3.132.0.35":
+ spec = new ECGenParameterSpec("secp521r1");
+ break;
+ default:
+ return false;
+ }
+ return verify(signature, data, pubkey, spec);
+
+ } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECGenParameterSpec params);
+ }
+
+ public static class NettleECDSAwithNONE extends Nettle {
+
+ public NettleECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java b/standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java
new file mode 100644
index 0000000..d7be4dc
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/output/TextTestWriter.java
@@ -0,0 +1,56 @@
+package cz.crcs.ectester.standalone.output;
+
+import cz.crcs.ectester.common.cli.Colors;
+import cz.crcs.ectester.common.output.BaseTextTestWriter;
+import cz.crcs.ectester.common.test.TestSuite;
+import cz.crcs.ectester.common.test.Testable;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.test.base.StandaloneTestable;
+import cz.crcs.ectester.standalone.test.suites.StandaloneTestSuite;
+
+import java.io.PrintStream;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class TextTestWriter extends BaseTextTestWriter {
+ public TextTestWriter(PrintStream output) {
+ super(output);
+ }
+
+ private String causeString(Object cause) {
+ if (cause == null) {
+ return "";
+ } else if (cause instanceof Exception) {
+ Exception ex = ((Exception) cause);
+ return " -> " + ex.getClass().getCanonicalName() + " : " + ex.getMessage();
+ } else {
+ return cause.toString();
+ }
+ }
+
+ @Override
+ protected String testableString(Testable t) {
+ if (t instanceof StandaloneTestable) {
+ StandaloneTestable<?> testable = (StandaloneTestable) t;
+ Enum<?> stage = testable.getStage();
+ String stageName = stage.name();
+ String exception = causeString(testable.getException());
+ String errorCause = causeString(testable.errorCause());
+ return String.format("[%d/%d] %s %s %s", stage.ordinal() + 1, stage.getClass().getEnumConstants().length, stageName, exception, errorCause);
+ }
+ return "";
+ }
+
+ @Override
+ protected String deviceString(TestSuite suite) {
+ if (suite instanceof StandaloneTestSuite) {
+ StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite;
+ StringBuilder sb = new StringBuilder();
+ sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterStandalone.VERSION).append(System.lineSeparator());
+ sb.append("═══ ").append(Colors.underline("Library:")).append(" ").append(standaloneSuite.getLibrary().name()).append(System.lineSeparator());
+ return sb.toString();
+ }
+ return "";
+ }
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java b/standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java
new file mode 100644
index 0000000..812634f
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/output/XMLTestWriter.java
@@ -0,0 +1,156 @@
+package cz.crcs.ectester.standalone.output;
+
+import cz.crcs.ectester.common.output.BaseXMLTestWriter;
+import cz.crcs.ectester.common.test.TestSuite;
+import cz.crcs.ectester.common.test.Testable;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+import cz.crcs.ectester.standalone.test.base.SignatureTestable;
+import cz.crcs.ectester.standalone.test.base.StandaloneTestable;
+import cz.crcs.ectester.standalone.test.suites.StandaloneTestSuite;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.OutputStream;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class XMLTestWriter extends BaseXMLTestWriter {
+
+ public XMLTestWriter(OutputStream output) throws ParserConfigurationException {
+ super(output);
+ }
+
+ private Element pkeyElement(PublicKey pkey) {
+ Element pubkey = doc.createElement("pubkey");
+ if (pkey == null) {
+ return pubkey;
+ }
+ pubkey.setAttribute("algorithm", pkey.getAlgorithm());
+ pubkey.setAttribute("format", pkey.getFormat());
+ pubkey.setTextContent(ByteUtil.bytesToHex(pkey.getEncoded()));
+ return pubkey;
+ }
+
+ private Element skeyElement(PrivateKey skey) {
+ Element privkey = doc.createElement("privkey");
+ if (skey == null) {
+ return privkey;
+ }
+ privkey.setAttribute("algorithm", skey.getAlgorithm());
+ privkey.setAttribute("format", skey.getFormat());
+ privkey.setTextContent(ByteUtil.bytesToHex(skey.getEncoded()));
+ return privkey;
+ }
+
+ private Element kaElement(KeyAgreementTestable kat) {
+ Element katElem = doc.createElement("key-agreement");
+ katElem.setAttribute("algo", kat.getKa().getAlgorithm());
+
+ Element secret = doc.createElement("secret");
+ secret.setTextContent(ByteUtil.bytesToHex(kat.getSecret()));
+ katElem.appendChild(secret);
+
+ PublicKey pkey = kat.getPublicKey();
+ Element pubkey = pkeyElement(pkey);
+ katElem.appendChild(pubkey);
+
+ PrivateKey skey = kat.getPrivateKey();
+ Element privkey = skeyElement(skey);
+ katElem.appendChild(privkey);
+
+ return katElem;
+ }
+
+ private Element kgtElement(KeyGeneratorTestable kgt) {
+ Element kgtElem = doc.createElement("key-pair-generator");
+ kgtElem.setAttribute("algo", kgt.getKpg().getAlgorithm());
+
+ Element keyPair = doc.createElement("key-pair");
+ if (kgt.getKeyPair() != null) {
+ PublicKey pkey = kgt.getKeyPair().getPublic();
+ Element pubkey = pkeyElement(pkey);
+ keyPair.appendChild(pubkey);
+
+ PrivateKey skey = kgt.getKeyPair().getPrivate();
+ Element privkey = skeyElement(skey);
+ keyPair.appendChild(privkey);
+ }
+
+ kgtElem.appendChild(keyPair);
+ return kgtElem;
+ }
+
+ private Element sigElement(SignatureTestable sig) {
+ Element sigElem = doc.createElement("signature");
+ sigElem.setAttribute("verified", sig.getVerified() ? "true" : "false");
+ sigElem.setAttribute("algo", sig.getSig().getAlgorithm());
+
+ Element raw = doc.createElement("raw");
+ raw.setTextContent(ByteUtil.bytesToHex(sig.getSignature()));
+ sigElem.appendChild(raw);
+
+ return sigElem;
+ }
+
+ private Element stageElement(StandaloneTestable<?> t) {
+ Element result = doc.createElement("stage");
+ result.setTextContent(t.getStage().name());
+ return result;
+ }
+
+ private String causeObject(Object cause) {
+ if (cause == null) {
+ return "";
+ } else if (cause instanceof Exception) {
+ Exception ex = ((Exception) cause);
+ return ex.getClass().getCanonicalName() + " : " + ex.getMessage();
+ } else {
+ return cause.toString();
+ }
+ }
+
+ @Override
+ protected Element testableElement(Testable t) {
+ Element result = doc.createElement("test");
+ if (t instanceof StandaloneTestable) {
+ StandaloneTestable<?> testable = (StandaloneTestable) t;
+ if (t instanceof KeyGeneratorTestable) {
+ result.setAttribute("type", "key-pair-generator");
+ result.appendChild(kgtElement((KeyGeneratorTestable) t));
+ } else if (t instanceof KeyAgreementTestable) {
+ result.setAttribute("type", "key-agreement");
+ result.appendChild(kaElement((KeyAgreementTestable) t));
+ } else if (t instanceof SignatureTestable) {
+ result.setAttribute("type", "signature");
+ result.appendChild(sigElement((SignatureTestable) t));
+ }
+ result.appendChild(stageElement(testable));
+ Element exception = doc.createElement("exception");
+ exception.setTextContent(causeObject(testable.getException()) + causeObject(testable.errorCause()));
+ result.appendChild(exception);
+ }
+ return result;
+ }
+
+ @Override
+ protected Element deviceElement(TestSuite suite) {
+ if (suite instanceof StandaloneTestSuite) {
+ StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite;
+ Element result = doc.createElement("device");
+ result.setAttribute("type", "library");
+ result.setAttribute("ectester", ECTesterStandalone.VERSION);
+
+ Element name = doc.createElement("name");
+ name.setTextContent(standaloneSuite.getLibrary().name());
+ result.appendChild(name);
+ return result;
+ }
+ return null;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java b/standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java
new file mode 100644
index 0000000..ee8a199
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/output/YAMLTestWriter.java
@@ -0,0 +1,124 @@
+package cz.crcs.ectester.standalone.output;
+
+import cz.crcs.ectester.common.output.BaseYAMLTestWriter;
+import cz.crcs.ectester.common.test.TestSuite;
+import cz.crcs.ectester.common.test.Testable;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+import cz.crcs.ectester.standalone.test.base.SignatureTestable;
+import cz.crcs.ectester.standalone.test.base.StandaloneTestable;
+import cz.crcs.ectester.standalone.test.suites.StandaloneTestSuite;
+
+import java.io.PrintStream;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class YAMLTestWriter extends BaseYAMLTestWriter {
+ public YAMLTestWriter(PrintStream output) {
+ super(output);
+ }
+
+ private Map<String, Object> keyObject(Key key) {
+ Map<String, Object> kObject = new LinkedHashMap<>();
+ if (key == null) {
+ return kObject;
+ }
+ kObject.put("algo", key.getAlgorithm());
+ kObject.put("format", key.getFormat());
+ kObject.put("raw", ByteUtil.bytesToHex(key.getEncoded()));
+ return kObject;
+ }
+
+ private Map<String, Object> kaObject(KeyAgreementTestable kat) {
+ Map<String, Object> katObject = new LinkedHashMap<>();
+ katObject.put("algo", kat.getKa().getAlgorithm());
+ katObject.put("secret", ByteUtil.bytesToHex(kat.getSecret()));
+
+ PublicKey pkey = kat.getPublicKey();
+ katObject.put("pubkey", keyObject(pkey));
+
+ PrivateKey skey = kat.getPrivateKey();
+ katObject.put("privkey", keyObject(skey));
+ return katObject;
+ }
+
+ private Map<String, Object> kgtObject(KeyGeneratorTestable kgt) {
+ Map<String, Object> kgtObject = new LinkedHashMap<>();
+ kgtObject.put("algo", kgt.getKpg().getAlgorithm());
+
+ Map<String, Object> keypair = new LinkedHashMap<>();
+ if (kgt.getKeyPair() != null) {
+ PublicKey pkey = kgt.getKeyPair().getPublic();
+ Map<String, Object> pubObject = keyObject(pkey);
+ keypair.put("pubkey", pubObject);
+
+ PrivateKey skey = kgt.getKeyPair().getPrivate();
+ Map<String, Object> privObject = keyObject(skey);
+ keypair.put("privkey", privObject);
+ }
+
+ kgtObject.put("keypair", keypair);
+ return kgtObject;
+ }
+
+ private Map<String, Object> sigObject(SignatureTestable sig) {
+ Map<String, Object> sigObject = new LinkedHashMap<>();
+ sigObject.put("algo", sig.getSig().getAlgorithm());
+ sigObject.put("verified", sig.getVerified());
+ sigObject.put("raw", ByteUtil.bytesToHex(sig.getSignature()));
+ return sigObject;
+ }
+
+ private String causeObject(Object cause) {
+ if (cause == null) {
+ return "";
+ } else if (cause instanceof Exception) {
+ Exception ex = ((Exception) cause);
+ return ex.getClass().getCanonicalName() + " : " + ex.getMessage();
+ } else {
+ return cause.toString();
+ }
+ }
+
+ @Override
+ protected Map<String, Object> testableObject(Testable t) {
+ Map<String, Object> result = new LinkedHashMap<>();
+ if (t instanceof StandaloneTestable) {
+ StandaloneTestable<?> testable = (StandaloneTestable) t;
+ if (t instanceof KeyGeneratorTestable) {
+ result.put("type", "key-pair-generator");
+ result.put("key-pair-generator", kgtObject((KeyGeneratorTestable) t));
+ } else if (t instanceof KeyAgreementTestable) {
+ result.put("type", "key-agreement");
+ result.put("key-agreement", kaObject((KeyAgreementTestable) t));
+ } else if (t instanceof SignatureTestable) {
+ result.put("type", "signature");
+ result.put("signature", sigObject((SignatureTestable) t));
+ }
+ result.put("stage", testable.getStage().name());
+ result.put("exception", causeObject(testable.getException()) + causeObject(testable.errorCause()));
+ }
+ return result;
+ }
+
+ @Override
+ protected Map<String, Object> deviceObject(TestSuite suite) {
+ if (suite instanceof StandaloneTestSuite) {
+ StandaloneTestSuite standaloneSuite = (StandaloneTestSuite) suite;
+ Map<String, Object> result = new LinkedHashMap<>();
+ result.put("type", "library");
+ result.put("ectester", ECTesterStandalone.VERSION);
+ result.put("name", standaloneSuite.getLibrary().name());
+ return result;
+ }
+ return null;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java
new file mode 100644
index 0000000..fd48212
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTest.java
@@ -0,0 +1,59 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.SimpleTest;
+import cz.crcs.ectester.common.test.TestCallback;
+
+import java.util.Arrays;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class KeyAgreementTest extends SimpleTest<KeyAgreementTestable> {
+ private KeyAgreementTest(KeyAgreementTestable ka, TestCallback<KeyAgreementTestable> callback) {
+ super(ka, callback);
+ }
+
+ public static KeyAgreementTest match(KeyAgreementTestable ka, byte[] expectedSecret) {
+ return new KeyAgreementTest(ka, new TestCallback<KeyAgreementTestable>() {
+ @Override
+ public Result apply(KeyAgreementTestable ka) {
+ if (Arrays.equals(ka.getSecret(), expectedSecret)) {
+ return new Result(Result.Value.SUCCESS, "The KeyAgreement result matched the expected derived secret.");
+ } else {
+ return new Result(Result.Value.FAILURE, "The KeyAgreement result did not match the expected derived secret.");
+ }
+ }
+ });
+ }
+
+ public static KeyAgreementTest expect(KeyAgreementTestable ka, Result.ExpectedValue expected) {
+ return new KeyAgreementTest(ka, new TestCallback<KeyAgreementTestable>() {
+ @Override
+ public Result apply(KeyAgreementTestable keyAgreementTestable) {
+ Result.Value value = Result.Value.fromExpected(expected, keyAgreementTestable.ok(), keyAgreementTestable.error());
+ return new Result(value, value.description());
+ }
+ });
+ }
+
+ public static KeyAgreementTest expectError(KeyAgreementTestable ka, Result.ExpectedValue expected) {
+ return new KeyAgreementTest(ka, new TestCallback<KeyAgreementTestable>() {
+ @Override
+ public Result apply(KeyAgreementTestable keyAgreementTestable) {
+ Result.Value value = Result.Value.fromExpected(expected, keyAgreementTestable.ok(), false);
+ return new Result(value, value.description());
+ }
+ });
+ }
+
+ public static KeyAgreementTest function(KeyAgreementTestable ka, TestCallback<KeyAgreementTestable> callback) {
+ return new KeyAgreementTest(ka, callback);
+ }
+
+ @Override
+ public String getDescription() {
+ String keyAlgo = testable.getKeyAlgorithm() == null ? "" : " (" + testable.getKeyAlgorithm() + ")";
+ return "KeyAgreement " + testable.getKa().getAlgorithm() + keyAlgo;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java
new file mode 100644
index 0000000..7fd1c5a
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java
@@ -0,0 +1,179 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class KeyAgreementTestable extends StandaloneTestable<KeyAgreementTestable.KeyAgreementStage> {
+ private KeyAgreement ka;
+ private ECPrivateKey privateKey;
+ private ECPublicKey publicKey;
+ private KeyGeneratorTestable kgtPrivate;
+ private KeyGeneratorTestable kgtPublic;
+ private AlgorithmParameterSpec spec;
+ private String keyAlgo;
+ private byte[] secret;
+ private SecretKey derived;
+
+ public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey) {
+ this.ka = ka;
+ this.privateKey = privateKey;
+ this.publicKey = publicKey;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey, String keyAlgo) {
+ this(ka, privateKey, publicKey);
+ this.keyAlgo = keyAlgo;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey, ECParameterSpec spec) {
+ this(ka, privateKey, publicKey);
+ this.spec = spec;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey, ECParameterSpec spec, String keyAlgo) {
+ this(ka, privateKey, publicKey, spec);
+ this.keyAlgo = keyAlgo;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable kgt, ECPrivateKey privateKey, ECParameterSpec spec) {
+ this(ka, privateKey, null, spec);
+ this.kgtPublic = kgt;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable kgt, ECPrivateKey privateKey, ECParameterSpec spec, String keyAlgo) {
+ this(ka, kgt, privateKey, spec);
+ this.keyAlgo = keyAlgo;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, ECPublicKey publicKey, KeyGeneratorTestable kgt, ECParameterSpec spec) {
+ this(ka, null, publicKey, spec);
+ this.kgtPrivate = kgt;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, ECPublicKey publicKey, KeyGeneratorTestable kgt, ECParameterSpec spec, String keyAlgo) {
+ this(ka, publicKey, kgt, spec);
+ this.keyAlgo = keyAlgo;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable privKgt, KeyGeneratorTestable pubKgt, ECParameterSpec spec) {
+ this(ka, (ECPrivateKey) null, null, spec);
+ this.kgtPrivate = privKgt;
+ this.kgtPublic = pubKgt;
+ }
+
+ public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable privKgt, KeyGeneratorTestable pubKgt, ECParameterSpec spec, String keyAlgo) {
+ this(ka, privKgt, pubKgt, spec);
+ this.keyAlgo = keyAlgo;
+ }
+
+ public String getKeyAlgorithm() {
+ return keyAlgo;
+ }
+
+ public KeyAgreement getKa() {
+ return ka;
+ }
+
+ public ECPublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ public ECPrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ public byte[] getSecret() {
+ if (!hasRun) {
+ return null;
+ }
+ return secret;
+ }
+
+ public SecretKey getDerivedKey() {
+ if (!hasRun) {
+ return null;
+ }
+ return derived;
+ }
+
+ @Override
+ public void run() {
+ try {
+ stage = KeyAgreementStage.GetPrivate;
+ if (kgtPrivate != null) {
+ privateKey = (ECPrivateKey) kgtPrivate.getKeyPair().getPrivate();
+ }
+
+ stage = KeyAgreementStage.GetPublic;
+ if (kgtPublic != null) {
+ publicKey = (ECPublicKey) kgtPublic.getKeyPair().getPublic();
+ }
+
+ stage = KeyAgreementStage.Init;
+ try {
+ if (spec != null) {
+ ka.init(privateKey, spec);
+ } else {
+ ka.init(privateKey);
+ }
+ } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+ failOnException(e);
+ return;
+ }
+
+ stage = KeyAgreementStage.DoPhase;
+ try {
+ ka.doPhase(publicKey, true);
+ } catch (IllegalStateException | InvalidKeyException e) {
+ failOnException(e);
+ return;
+ }
+
+ stage = KeyAgreementStage.GenerateSecret;
+ try {
+ if (keyAlgo != null) {
+ derived = ka.generateSecret(keyAlgo);
+ secret = derived.getEncoded();
+ } else {
+ secret = ka.generateSecret();
+ }
+ } catch (IllegalStateException | UnsupportedOperationException e) {
+ failOnException(e);
+ return;
+ }
+
+ ok = true;
+ } catch (Exception ex) {
+ ok = false;
+ error = true;
+ errorCause = ex;
+ }
+ hasRun = true;
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ try {
+ ka = KeyAgreement.getInstance(ka.getAlgorithm(), ka.getProvider());
+ } catch (NoSuchAlgorithmException e) { }
+ }
+
+ public enum KeyAgreementStage {
+ GetPrivate,
+ GetPublic,
+ Init,
+ DoPhase,
+ GenerateSecret
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java
new file mode 100644
index 0000000..32f82cb
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTest.java
@@ -0,0 +1,43 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.SimpleTest;
+import cz.crcs.ectester.common.test.TestCallback;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class KeyGeneratorTest extends SimpleTest<KeyGeneratorTestable> {
+ private KeyGeneratorTest(KeyGeneratorTestable kg, TestCallback<KeyGeneratorTestable> callback) {
+ super(kg, callback);
+ }
+
+ public static KeyGeneratorTest expect(KeyGeneratorTestable kg, Result.ExpectedValue expected) {
+ return new KeyGeneratorTest(kg, new TestCallback<KeyGeneratorTestable>() {
+ @Override
+ public Result apply(KeyGeneratorTestable keyGenerationTestable) {
+ Result.Value value = Result.Value.fromExpected(expected, keyGenerationTestable.ok(), keyGenerationTestable.error());
+ return new Result(value, value.description());
+ }
+ });
+ }
+
+ public static KeyGeneratorTest expectError(KeyGeneratorTestable kg, Result.ExpectedValue expected) {
+ return new KeyGeneratorTest(kg, new TestCallback<KeyGeneratorTestable>() {
+ @Override
+ public Result apply(KeyGeneratorTestable keyGenerationTestable) {
+ Result.Value value = Result.Value.fromExpected(expected, keyGenerationTestable.ok(), false);
+ return new Result(value, value.description());
+ }
+ });
+ }
+
+ public static KeyGeneratorTest function(KeyGeneratorTestable ka, TestCallback<KeyGeneratorTestable> callback) {
+ return new KeyGeneratorTest(ka, callback);
+ }
+
+ @Override
+ public String getDescription() {
+ return "KeyPairGenerator " + testable.getKpg().getAlgorithm();
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java
new file mode 100644
index 0000000..c05d6e3
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/KeyGeneratorTestable.java
@@ -0,0 +1,70 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class KeyGeneratorTestable extends StandaloneTestable<KeyGeneratorTestable.KeyGeneratorStage> {
+ private KeyPair kp;
+ private KeyPairGenerator kpg;
+ private int keysize = 0;
+ private ECParameterSpec spec = null;
+
+ public KeyGeneratorTestable(KeyPairGenerator kpg) {
+ this.kpg = kpg;
+ }
+
+ public KeyGeneratorTestable(KeyPairGenerator kpg, int keysize) {
+ this.kpg = kpg;
+ this.keysize = keysize;
+ }
+
+ public KeyGeneratorTestable(KeyPairGenerator kpg, ECParameterSpec spec) {
+ this.kpg = kpg;
+ this.spec = spec;
+ }
+
+ public KeyPairGenerator getKpg() {
+ return kpg;
+ }
+
+ public KeyPair getKeyPair() {
+ return kp;
+ }
+
+ @Override
+ public void run() {
+ try {
+ stage = KeyGeneratorStage.Init;
+ try {
+ if (spec != null) {
+ kpg.initialize(spec);
+ } else if (keysize != 0) {
+ kpg.initialize(keysize);
+ }
+ } catch (InvalidAlgorithmParameterException e) {
+ failOnException(e);
+ return;
+ }
+
+ stage = KeyGeneratorStage.GenKeyPair;
+ kp = kpg.genKeyPair();
+
+ ok = true;
+ } catch (Exception ex) {
+ ok = false;
+ error = true;
+ errorCause = ex;
+ }
+ hasRun = true;
+ }
+
+ public enum KeyGeneratorStage {
+ Init,
+ GenKeyPair
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/PerformanceTest.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/PerformanceTest.java
new file mode 100644
index 0000000..258ca12
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/PerformanceTest.java
@@ -0,0 +1,109 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import cz.crcs.ectester.common.test.BaseTestable;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.SimpleTest;
+import cz.crcs.ectester.common.test.TestCallback;
+
+import java.util.Arrays;
+
+/**
+ * @author David Hofman
+ */
+public class PerformanceTest extends SimpleTest<BaseTestable> {
+ private long[] times;
+ private long mean;
+ private long median;
+ private long mode;
+ private final int count;
+ private final String desc;
+
+ private PerformanceTest(BaseTestable testable, int count, String desc) {
+ super(testable, new TestCallback<BaseTestable>() {
+ @Override
+ public Result apply(BaseTestable testable) {
+ return new Result(Result.Value.SUCCESS);
+ }
+ });
+ this.count = count;
+ this.desc = desc;
+ }
+
+ public static PerformanceTest repeat(BaseTestable testable, int count) {
+ return new PerformanceTest(testable, count, null);
+ }
+
+ public static PerformanceTest repeat(BaseTestable testable, String desc, int count) {
+ return new PerformanceTest(testable, count, desc);
+ }
+
+ @Override
+ public String getDescription() {
+ String rest = String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode);
+ return (desc == null ? rest : desc + " (" + rest + ")");
+ }
+
+ @Override
+ protected void runSelf() {
+
+ times = new long[count];
+ for (int i = 0; i < count; ++i) {
+ times[i] = measureTime();
+ }
+
+ mean = Arrays.stream(times).sum() / count;
+
+ long[] sorted = times.clone();
+ Arrays.sort(sorted);
+ if (count % 2 == 0) {
+ median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2;
+ } else {
+ median = sorted[count / 2];
+ }
+
+ long max_occurrences = 0;
+ int i = 0;
+ while (i < count) {
+ long current_value = sorted[i];
+ long current_occurrences = 0;
+ while (i < count && sorted[i] == current_value) {
+ i++;
+ current_occurrences++;
+ }
+ if (current_occurrences > max_occurrences) {
+ max_occurrences = current_occurrences;
+ mode = current_value;
+ }
+ }
+ result = callback.apply(testable);
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public long[] getTimes() {
+ return times;
+ }
+
+ public long getMean() {
+ return mean;
+ }
+
+ public long getMedian() {
+ return median;
+ }
+
+ public long getMode() {
+ return mode;
+ }
+
+ private long measureTime() {
+ if(testable.hasRun()) {
+ testable.reset();
+ }
+ long startTime = System.nanoTime();
+ testable.run();
+ return System.nanoTime() - startTime;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTest.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTest.java
new file mode 100644
index 0000000..a817691
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTest.java
@@ -0,0 +1,43 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.SimpleTest;
+import cz.crcs.ectester.common.test.TestCallback;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class SignatureTest extends SimpleTest<SignatureTestable> {
+ private SignatureTest(SignatureTestable sig, TestCallback<SignatureTestable> callback) {
+ super(sig, callback);
+ }
+
+ public static SignatureTest expect(SignatureTestable kg, Result.ExpectedValue expected) {
+ return new SignatureTest(kg, new TestCallback<SignatureTestable>() {
+ @Override
+ public Result apply(SignatureTestable signatureTestable) {
+ Result.Value value = Result.Value.fromExpected(expected, signatureTestable.ok(), signatureTestable.error());
+ return new Result(value, value.description());
+ }
+ });
+ }
+
+ public static SignatureTest expectError(SignatureTestable kg, Result.ExpectedValue expected) {
+ return new SignatureTest(kg, new TestCallback<SignatureTestable>() {
+ @Override
+ public Result apply(SignatureTestable signatureTestable) {
+ Result.Value value = Result.Value.fromExpected(expected, signatureTestable.ok(), false);
+ return new Result(value, value.description());
+ }
+ });
+ }
+
+ public static SignatureTest function(SignatureTestable ka, TestCallback<SignatureTestable> callback) {
+ return new SignatureTest(ka, callback);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Signature " + testable.getSig().getAlgorithm();
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTestable.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTestable.java
new file mode 100644
index 0000000..fe81b10
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/SignatureTestable.java
@@ -0,0 +1,143 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class SignatureTestable extends StandaloneTestable<SignatureTestable.SignatureStage> {
+ private Signature sig;
+ private ECPrivateKey signKey;
+ private ECPublicKey verifyKey;
+ private KeyGeneratorTestable kgt;
+ private byte[] data;
+ private byte[] signature;
+ private boolean verified;
+
+ public SignatureTestable(Signature sig, ECPrivateKey signKey, ECPublicKey verifyKey, byte[] data) {
+ this.sig = sig;
+ this.signKey = signKey;
+ this.verifyKey = verifyKey;
+ this.data = data;
+ if (data == null) {
+ SecureRandom random = new SecureRandom();
+ this.data = new byte[64];
+ random.nextBytes(this.data);
+ }
+ }
+
+ public SignatureTestable(Signature sig, ECPublicKey verifyKey, byte[] data, byte[] signature) {
+ this.sig = sig;
+ this.verifyKey = verifyKey;
+ this.data = data;
+ this.signature = signature;
+ }
+
+ public SignatureTestable(Signature sig, KeyGeneratorTestable kgt, byte[] data) {
+ this(sig, (ECPrivateKey) null, null, data);
+ this.kgt = kgt;
+ }
+
+ public Signature getSig() {
+ return sig;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public byte[] getSignature() {
+ return signature;
+ }
+
+ public boolean getVerified() {
+ return verified;
+ }
+
+ @Override
+ public void run() {
+ try {
+ stage = SignatureStage.GetKeys;
+ if (kgt != null) {
+ signKey = (ECPrivateKey) kgt.getKeyPair().getPrivate();
+ verifyKey = (ECPublicKey) kgt.getKeyPair().getPublic();
+ }
+
+ if(signKey != null) {
+ stage = SignatureStage.InitSign;
+ try {
+ sig.initSign(signKey);
+ } catch (InvalidKeyException e) {
+ failOnException(e);
+ return;
+ }
+
+ stage = SignatureStage.UpdateSign;
+ try {
+ sig.update(data);
+ } catch (SignatureException e) {
+ failOnException(e);
+ return;
+ }
+
+ stage = SignatureStage.Sign;
+ try {
+ signature = sig.sign();
+ } catch (SignatureException e) {
+ failOnException(e);
+ return;
+ }
+
+ ok = true;
+ }
+
+ if (verifyKey != null) {
+ stage = SignatureStage.InitVerify;
+ try {
+ sig.initVerify(verifyKey);
+ } catch (InvalidKeyException e) {
+ failOnException(e);
+ return;
+ }
+
+ stage = SignatureStage.UpdateVerify;
+ try {
+ sig.update(data);
+ } catch (SignatureException e) {
+ failOnException(e);
+ return;
+ }
+
+ stage = SignatureStage.Verify;
+ try {
+ verified = sig.verify(signature);
+ } catch (SignatureException e) {
+ failOnException(e);
+ return;
+ }
+
+ ok = verified;
+ }
+ } catch (Exception ex) {
+ ok = false;
+ error = true;
+ errorCause = ex;
+ }
+ hasRun = true;
+ }
+
+ public enum SignatureStage {
+ GetKeys,
+ InitSign,
+ UpdateSign,
+ Sign,
+ InitVerify,
+ UpdateVerify,
+ Verify
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java
new file mode 100644
index 0000000..47bffc1
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/base/StandaloneTestable.java
@@ -0,0 +1,25 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import cz.crcs.ectester.common.test.BaseTestable;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class StandaloneTestable<T extends Enum<T>> extends BaseTestable {
+ protected T stage;
+ protected Exception exception;
+
+ public T getStage() {
+ return stage;
+ }
+
+ public Exception getException() {
+ return exception;
+ }
+
+ protected void failOnException(Exception ex) {
+ ok = false;
+ hasRun = true;
+ exception = ex;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java
new file mode 100644
index 0000000..52b0fbf
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCofactorSuite.java
@@ -0,0 +1,111 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTest;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTest;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneCofactorSuite extends StandaloneTestSuite {
+ public StandaloneCofactorSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "cofactor", "The cofactor test suite tests whether the library correctly rejects points on the curve",
+ "but not in the subgroup generated by the generator (so of small order, dividing the cofactor) during ECDH.",
+ "Supports options:", "\t - gt/kpg-type", "\t - kt/ka-type (select multiple types by separating them with commas)");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ List<String> kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "cofactor");
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+ ECParameterSpec spec = curve.toSpec();
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp == null) {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", generateFail));
+ continue;
+ }
+ Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+
+ List<Test> allKaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ List<Test> specificKaTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ ECPublicKey ecpub = ECUtil.toPublicKey(pub);
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ Test keyAgreement = KeyAgreementTest.expectError(testable, Result.ExpectedValue.FAILURE);
+ specificKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " cofactor key test.", keyAgreement));
+ }
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with public points on non-generator subgroup.", specificKaTests.toArray(new Test[0])));
+ }
+ }
+ if(allKaTests.isEmpty()) {
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library."));
+ }
+ Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0]));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", generateSuccess, tests));
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java
new file mode 100644
index 0000000..c59d864
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneCompositeSuite.java
@@ -0,0 +1,210 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import cz.crcs.ectester.standalone.test.base.*;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneCompositeSuite extends StandaloneTestSuite {
+ private String kpgAlgo;
+ private String kaAlgo;
+ private String sigAlgo;
+ private List<String> kaTypes;
+ private List<String> sigTypes;
+
+ public StandaloneCompositeSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "composite", "The composite suite runs ECDH over curves with composite order.",
+ "Various types of compositeness is tested: smooth numbers, Carmichael pseudo-prime, prime square, product of two large primes.",
+ "Supports options:",
+ "\t - gt/kpg-type",
+ "\t - kt/ka-type (select multiple types by separating them with commas)",
+ "\t - st/sig-type (select multiple types by separating them with commas)");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ kpgAlgo = cli.getOptionValue("test.kpg-type");
+ kaAlgo = cli.getOptionValue("test.ka-type");
+ sigAlgo = cli.getOptionValue("test.sig-type");
+ kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+ sigTypes = sigAlgo != null ? Arrays.asList(sigAlgo.split(",")) : new ArrayList<>();
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+
+ Map<String, EC_Key.Public> keys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "composite");
+ Map<EC_Curve, List<EC_Key.Public>> mappedKeys = EC_Store.mapKeyToCurve(keys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> curveKeys : mappedKeys.entrySet()) {
+ EC_Curve curve = curveKeys.getKey();
+ ECParameterSpec spec = curve.toSpec();
+
+ //Generate KeyPair
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp == null) {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", generateFail));
+ continue;
+ }
+ Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+
+ //Perform KeyAgreement tests
+ List<Test> allKaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ List<Test> specificKaTests = new LinkedList<>();
+ for (EC_Key.Public pub : curveKeys.getValue()) {
+ ECPublicKey ecpub = ECUtil.toPublicKey(pub);
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv ,ecpub);
+ Test keyAgreement = KeyAgreementTest.expectError(testable, Result.ExpectedValue.FAILURE);
+ specificKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", with generated private key, " + pub.getDesc(), keyAgreement));
+ }
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with various public points.", specificKaTests.toArray(new Test[0])));
+ }
+ }
+ if(allKaTests.isEmpty()) {
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library."));
+ }
+ Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0]));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", generateSuccess, tests));
+ }
+
+
+ Map<String, EC_Curve> results = EC_Store.getInstance().getObjects(EC_Curve.class, "composite");
+ Map<String, List<EC_Curve>> groups = EC_Store.mapToPrefix(results.values());
+ /* Test the whole curves with both keypairs generated by the library(no small-order public points provided).
+ */
+ List<EC_Curve> wholeCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("whole")).findFirst().get().getValue();
+ testGroup(wholeCurves, kpg, "Composite generator order", Result.ExpectedValue.FAILURE);
+
+ /* Also test having a G of small order, so small R.
+ */
+ List<EC_Curve> smallRCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("small")).findFirst().get().getValue();
+ testGroup(smallRCurves, kpg, "Small generator order", Result.ExpectedValue.FAILURE);
+
+ /* Test increasingly larger prime R, to determine where/if the behavior changes.
+ */
+ List<EC_Curve> varyingCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("varying")).findFirst().get().getValue();
+ testGroup(varyingCurves, kpg, null, Result.ExpectedValue.ANY);
+
+ /* Also test having a G of large but composite order, R = p * q,
+ */
+ List<EC_Curve> pqCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pq")).findFirst().get().getValue();
+ testGroup(pqCurves, kpg, null, Result.ExpectedValue.ANY);
+
+ /* Also test having G or large order being a Carmichael pseudoprime, R = p * q * r,
+ */
+ List<EC_Curve> ppCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pp")).findFirst().get().getValue();
+ testGroup(ppCurves, kpg, "Generator order = Carmichael pseudo-prime", Result.ExpectedValue.ANY);
+
+ /* Also test rg0 curves.
+ */
+ List<EC_Curve> rg0Curves = groups.entrySet().stream().filter((e) -> e.getKey().equals("rg0")).findFirst().get().getValue();
+ testGroup(rg0Curves, kpg, null, Result.ExpectedValue.ANY);
+ }
+
+ private void testGroup(List<EC_Curve> curves, KeyPairGenerator kpg, String testName, Result.ExpectedValue dhValue) throws Exception {
+ for (EC_Curve curve : curves) {
+ String description;
+ if (testName == null) {
+ description = curve.getDesc() + " test of " + curve.getId() + ".";
+ } else {
+ description = testName + " test of " + curve.getId() + ".";
+ }
+
+ //generate KeyPair
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, curve.toSpec());
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp == null) {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() +
+ ". " + " Other tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, description, generateFail));
+ continue;
+ }
+ Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+ ECPublicKey ecpub = (ECPublicKey) kp.getPublic();
+
+ //perform KeyAgreement tests
+ List<Test> kaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ kaTests.add(KeyAgreementTest.expectError(testable, dhValue));
+ }
+ }
+ if(kaTests.isEmpty()) {
+ kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified KeyAgreement types is supported by the library."));
+ }
+
+ //perform Signature tests
+ List<Test> sigTests = new LinkedList<>();
+ for (SignatureIdent sigIdent : cfg.selected.getSigs()) {
+ if (sigAlgo == null || sigIdent.containsAny(sigTypes)) {
+ Signature sig = sigIdent.getInstance(cfg.selected.getProvider());
+ SignatureTestable testable = new SignatureTestable(sig, ecpriv, ecpub, null);
+ sigTests.add(SignatureTest.expectError(testable, dhValue));
+ }
+ }
+ if(sigTests.isEmpty()) {
+ sigTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library."));
+ }
+
+ Test performKeyAgreements = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform specified KeyAgreements.", kaTests.toArray(new Test[0]));
+ Test performSignatures = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform specified Signatures.", sigTests.toArray(new Test[0]));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, description, generateSuccess, performKeyAgreements, performSignatures));
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java
new file mode 100644
index 0000000..1c14ecc
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDefaultSuite.java
@@ -0,0 +1,108 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import cz.crcs.ectester.standalone.test.base.*;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.spec.ECParameterSpec;
+import java.util.Optional;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class StandaloneDefaultSuite extends StandaloneTestSuite {
+
+ public StandaloneDefaultSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "default", "The default test suite run basic support of ECDH and ECDSA.", "Supports options:", "\t - gt/kpg-type", "\t - kt/ka-type", "\t - st/sig-type", "\t - key-type");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ String sigAlgo = cli.getOptionValue("test.sig-type");
+ String keyAlgo = cli.getOptionValue("test.key-type", "AES");
+
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+
+ KeyGeneratorTestable kgtOne;
+ KeyGeneratorTestable kgtOther;
+ ECParameterSpec spec = null;
+ if (cli.hasOption("test.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("test.bits"));
+ kgtOne = new KeyGeneratorTestable(kpg, bits);
+ kgtOther = new KeyGeneratorTestable(kpg, bits);
+ } else if (cli.hasOption("test.named-curve")) {
+ String curveName = cli.getOptionValue("test.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ spec = curve.toSpec();
+ kgtOne = new KeyGeneratorTestable(kpg, spec);
+ kgtOther = new KeyGeneratorTestable(kpg, spec);
+ } else {
+ kgtOne = new KeyGeneratorTestable(kpg);
+ kgtOther = new KeyGeneratorTestable(kpg);
+ }
+
+ doTest(KeyGeneratorTest.expect(kgtOne, Result.ExpectedValue.SUCCESS));
+ doTest(KeyGeneratorTest.expect(kgtOther, Result.ExpectedValue.SUCCESS));
+
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.contains(kaAlgo)) {
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable;
+ if (kaIdent.requiresKeyAlgo()) {
+ testable = new KeyAgreementTestable(ka, kgtOne, kgtOther, spec, keyAlgo);
+ } else {
+ testable = new KeyAgreementTestable(ka, kgtOne, kgtOther, spec);
+ }
+ doTest(KeyAgreementTest.expect(testable, Result.ExpectedValue.SUCCESS));
+ }
+ }
+ for (SignatureIdent sigIdent : cfg.selected.getSigs()) {
+ if (sigAlgo == null || sigIdent.contains(sigAlgo)) {
+ Signature sig = sigIdent.getInstance(cfg.selected.getProvider());
+ doTest(SignatureTest.expect(new SignatureTestable(sig, kgtOne, null), Result.ExpectedValue.SUCCESS));
+ }
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java
new file mode 100644
index 0000000..9ab8a39
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneDegenerateSuite.java
@@ -0,0 +1,121 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTest;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTest;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneDegenerateSuite extends StandaloneTestSuite {
+ public StandaloneDegenerateSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "degenerate", "The degenerate suite tests whether the library rejects points outside of the curve during ECDH.",
+ "The tested points lie on a part of the plane for which some Edwards, Hessian and Huff form addition formulas degenerate into exponentiation in the base finite field.",
+ "Supports options:", "\t - gt/kpg-type", "\t - kt/ka-type (select multiple types by separating them with commas)");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ List<String> kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "degenerate");
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+ ECParameterSpec spec = curve.toSpec();
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+
+ Test generateSuccess;
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp != null) {
+ generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ } else { //If KeyPair generation fails, try generating it on a default curve instead. Use this key only if it has the same domain parameters as our public key.
+ KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits());
+ Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY);
+ runTest(generateOnDefaultCurve);
+ kp = kgtOnDefaultCurve.getKeyPair();
+ if(kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) {
+ generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generateOnDefaultCurve);
+ } else {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", generateFail));
+ continue;
+ }
+ }
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+
+ List<Test> allKaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ List<Test> specificKaTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ ECPublicKey ecpub = ECUtil.toPublicKey(pub);
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ Test keyAgreement = KeyAgreementTest.expectError(testable, Result.ExpectedValue.FAILURE);
+ specificKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " degenerate key test.", keyAgreement));
+ }
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with degenerate public points..", specificKaTests.toArray(new Test[0])));
+ }
+ }
+ if(allKaTests.isEmpty()) {
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library."));
+ }
+ Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0]));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", generateSuccess, tests));
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java
new file mode 100644
index 0000000..1900bea
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneEdgeCasesSuite.java
@@ -0,0 +1,313 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.*;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.test.TestCallback;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTest;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTest;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+
+import javax.crypto.KeyAgreement;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneEdgeCasesSuite extends StandaloneTestSuite {
+ KeyAgreementIdent kaIdent;
+
+ public StandaloneEdgeCasesSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "edge-cases", "The edge-cases test suite tests various inputs to ECDH which may cause an implementation to achieve a certain edge-case state during it.",
+ "Some of the data is from the google/Wycheproof project. Tests include CVE-2017-10176 and CVE-2017-8932.",
+ "Also tests values of the private key and public key that would trigger the OpenSSL modular multiplication bug on the P-256 curve.",
+ "Various edge private key values are also tested.",
+ "Supports options:",
+ "\t - gt/kpg-type",
+ "\t - kt/ka-type");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+
+ if (kaAlgo == null) {
+ // try ECDH, if not, fail with: need to specify ka algo.
+ Optional<KeyAgreementIdent> kaIdentOpt = cfg.selected.getKAs().stream()
+ .filter((ident) -> ident.contains("ECDH"))
+ .findFirst();
+ if (kaIdentOpt.isPresent()) {
+ kaIdent = kaIdentOpt.get();
+ } else {
+ System.err.println("The default KeyAgreement algorithm type of \"ECDH\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong ka algo/not found.
+ Optional<KeyAgreementIdent> kaIdentOpt = cfg.selected.getKAs().stream()
+ .filter((ident) -> ident.contains(kaAlgo))
+ .findFirst();
+ if (kaIdentOpt.isPresent()) {
+ kaIdent = kaIdentOpt.get();
+ } else {
+ System.err.println("The KeyAgreement algorithm type of \"" + kaAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+
+ Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "wycheproof");
+ Map<String, List<EC_KAResult>> groups = EC_Store.mapToPrefix(results.values());
+ for (Map.Entry<String, List<EC_KAResult>> e : groups.entrySet()) {
+ String description = null;
+ switch (e.getKey()) {
+ case "addsub":
+ description = "Tests for addition-subtraction chains.";
+ break;
+ case "cve_2017_10176":
+ description = "Tests for CVE-2017-10176.";
+ break;
+ case "cve_2017_8932":
+ description = "Tests for CVE-2017-8932.";
+ break;
+ }
+
+ List<Test> groupTests = new LinkedList<>();
+ Map<EC_Curve, List<EC_KAResult>> curveList = EC_Store.mapResultToCurve(e.getValue());
+ for (Map.Entry<EC_Curve, List<EC_KAResult>> c : curveList.entrySet()) {
+ EC_Curve curve = c.getKey();
+
+ List<Test> curveTests = new LinkedList<>();
+ List<EC_KAResult> values = c.getValue();
+ for (EC_KAResult value : values) {
+ String id = value.getId();
+ String privkeyId = value.getOneKey();
+ String pubkeyId = value.getOtherKey();
+ ECPrivateKey ecpriv = ECUtil.toPrivateKey(EC_Store.getInstance().getObject(EC_Key.Private.class, privkeyId));
+ ECPublicKey ecpub = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, pubkeyId));
+
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ Test ecdh = KeyAgreementTest.match(testable, value.getData(0));
+ Test one = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test " + id + ".", ecdh);
+ curveTests.add(one);
+ }
+ groupTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests on " + curve.getId() + ".", curveTests.toArray(new Test[0])));
+ }
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, description, groupTests.toArray(new Test[0])));
+ }
+
+ {
+ EC_KAResult openssl_bug = EC_Store.getInstance().getObject(EC_KAResult.class, "misc", "openssl-bug");
+ ECPrivateKey ecpriv = ECUtil.toPrivateKey(EC_Store.getInstance().getObject(EC_Key.Private.class, openssl_bug.getOtherKey()));
+ ECPublicKey ecpub = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, openssl_bug.getOneKey()));
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ Test ecdh = KeyAgreementTest.function(testable, new TestCallback<KeyAgreementTestable>() {
+ @Override
+ public Result apply(KeyAgreementTestable testable) {
+ if (!testable.ok()) {
+ return new Result(Result.Value.FAILURE, "ECDH was unsuccessful.");
+ }
+ if (ByteUtil.compareBytes(testable.getSecret(), 0, openssl_bug.getData(0), 0, testable.getSecret().length)) {
+ return new Result(Result.Value.FAILURE, "OpenSSL bug is present, derived secret matches example.");
+ }
+ return new Result(Result.Value.SUCCESS);
+ }
+ });
+
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test OpenSSL modular reduction bug.", ecdh));
+ }
+
+ Map<String, EC_Curve> curveMap = EC_Store.getInstance().getObjects(EC_Curve.class, "secg");
+ List<EC_Curve> curves = curveMap.entrySet().stream().filter((e) ->
+ e.getKey().endsWith("r1") && e.getValue().getField() == javacard.security.KeyPair.ALG_EC_FP).map(Map.Entry::getValue).collect(Collectors.toList());
+ curves.add(EC_Store.getInstance().getObject(EC_Curve.class, "cofactor/cofactor128p2"));
+ curves.add(EC_Store.getInstance().getObject(EC_Curve.class, "cofactor/cofactor160p4"));
+ Random rand = new Random();
+ for (EC_Curve curve : curves) {
+ ECParameterSpec spec = curve.toSpec();
+
+ //generate KeyPair
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if (kp == null) {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() +
+ ". " + " Other tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over" + curve.getId() + ".", generateFail));
+ continue;
+ }
+ Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate KeyPair.", generate);
+ ECPublicKey ecpub = (ECPublicKey) kp.getPublic();
+
+ //perform ECDH tests
+ Test zeroS = ecdhTest(ecpub, BigInteger.ZERO, spec, "ECDH with S = 0.", Result.ExpectedValue.FAILURE);
+ Test oneS = ecdhTest(ecpub, BigInteger.ONE, spec, "ECDH with S = 1.", Result.ExpectedValue.FAILURE);
+
+ byte[] rParam = curve.getParam(EC_Consts.PARAMETER_R)[0];
+ BigInteger R = new BigInteger(1, rParam);
+ BigInteger smaller = new BigInteger(curve.getBits(), rand).mod(R);
+ BigInteger diff = R.divide(BigInteger.valueOf(10));
+ BigInteger randDiff = new BigInteger(diff.bitLength(), rand).mod(diff);
+ BigInteger larger = R.add(randDiff);
+ BigInteger full = BigInteger.valueOf(1).shiftLeft(R.bitLength() - 1).subtract(BigInteger.ONE);
+
+ BigInteger alternate = full;
+ for (int i = 0; i < R.bitLength(); i += 2) {
+ alternate = alternate.clearBit(i);
+ }
+
+ BigInteger alternateOther = alternate.xor(full);
+ BigInteger rm1 = R.subtract(BigInteger.ONE);
+ BigInteger rp1 = R.add(BigInteger.ONE);
+
+ Test alternateS = ecdhTest(ecpub, alternate, spec, "ECDH with S = 101010101...01010.", Result.ExpectedValue.SUCCESS);
+ Test alternateOtherS = ecdhTest(ecpub, alternateOther, spec, "ECDH with S = 010101010...10101.", Result.ExpectedValue.SUCCESS);
+ Test fullS = ecdhTest(ecpub, full, spec, "ECDH with S = 111111111...11111 (but < r).", Result.ExpectedValue.SUCCESS);
+ Test smallerS = ecdhTest(ecpub, smaller, spec, "ECDH with S < r.", Result.ExpectedValue.SUCCESS);
+ Test exactS = ecdhTest(ecpub, R, spec, "ECDH with S = r.", Result.ExpectedValue.FAILURE);
+ Test largeS = ecdhTest(ecpub, larger, spec, "ECDH with S > r.", Result.ExpectedValue.ANY);
+ Test rm1S = ecdhTest(ecpub, rm1, spec, "ECDH with S = r - 1.", Result.ExpectedValue.SUCCESS);
+ Test rp1S = ecdhTest(ecpub, rp1, spec, "ECDH with S = r + 1.", Result.ExpectedValue.ANY);
+
+ byte[] k = curve.getParam(EC_Consts.PARAMETER_K)[0];
+ BigInteger K = new BigInteger(1, k);
+ BigInteger kr = K.multiply(R);
+ BigInteger krm1 = kr.subtract(BigInteger.ONE);
+ BigInteger krp1 = kr.add(BigInteger.ONE);
+
+ Result.ExpectedValue kExpected = K.equals(BigInteger.ONE) ? Result.ExpectedValue.SUCCESS : Result.ExpectedValue.FAILURE;
+
+ Test krS /*ONE!*/ = ecdhTest(ecpub, kr, spec, "ECDH with S = k * r.", Result.ExpectedValue.FAILURE);
+ Test krm1S = ecdhTest(ecpub, krm1, spec, "ECDH with S = (k * r) - 1.", kExpected);
+ Test krp1S = ecdhTest(ecpub, krp1, spec, "ECDH with S = (k * r) + 1.", Result.ExpectedValue.ANY);
+
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".",
+ generateSuccess, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largeS, rm1S, rp1S, krS, krm1S, krp1S));
+ }
+
+ EC_Curve secp160r1 = EC_Store.getInstance().getObject(EC_Curve.class, "secg/secp160r1");
+ ECParameterSpec spec = secp160r1.toSpec();
+ byte[] pData = secp160r1.getParam(EC_Consts.PARAMETER_FP)[0];
+ BigInteger p = new BigInteger(1, pData);
+ byte[] rData = secp160r1.getParam(EC_Consts.PARAMETER_R)[0];
+ BigInteger r = new BigInteger(1, rData);
+
+ BigInteger range = r.subtract(p);
+ BigInteger deviation = range.divide(BigInteger.valueOf(5));
+ BigDecimal dev = new BigDecimal(deviation);
+ BigDecimal smallDev = new BigDecimal(10000);
+ int n = 10;
+ BigInteger[] rs = new BigInteger[n];
+ BigInteger[] ps = new BigInteger[n];
+ BigInteger[] zeros = new BigInteger[n];
+ for (int i = 0; i < n; ++i) {
+ double sample;
+ do {
+ sample = rand.nextGaussian();
+ } while (sample >= -1 && sample <= 1);
+ BigInteger where = dev.multiply(new BigDecimal(sample)).toBigInteger();
+ rs[i] = where.add(r);
+ ps[i] = where.add(p);
+ zeros[i] = smallDev.multiply(new BigDecimal(sample)).toBigInteger().abs();
+ }
+ Arrays.sort(rs);
+ Arrays.sort(ps);
+ Arrays.sort(zeros);
+
+ //generate KeyPair
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp == null) {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on "
+ + secp160r1.getBits() + "b secp160r1." + " Other tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test private key values near zero, near p and near/larger than the order on" + secp160r1.getId() + ".", generateFail));
+ return;
+ }
+ Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate KeyPair.", generate);
+ ECPublicKey ecpub = (ECPublicKey) kp.getPublic();
+
+ //perform ECDH tests
+ Test[] zeroTests = new Test[n];
+ int i = 0;
+ for (BigInteger nearZero : zeros) {
+ zeroTests[i++] = ecdhTest(ecpub, nearZero, spec, nearZero.toString(16), Result.ExpectedValue.SUCCESS);
+ }
+ Test zeroTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near zero.", zeroTests);
+
+ Test[] pTests = new Test[n];
+ i = 0;
+ for (BigInteger nearP : ps) {
+ pTests[i++] = ecdhTest(ecpub, nearP, spec, nearP.toString(16) + (nearP.compareTo(p) > 0 ? " (>p)" : " (<=p)"), Result.ExpectedValue.SUCCESS);
+ }
+ Test pTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near p.", pTests);
+
+ Test[] rTests = new Test[n];
+ i = 0;
+ for (BigInteger nearR : rs) {
+ if (nearR.compareTo(r) >= 0) {
+ rTests[i++] = ecdhTest(ecpub, nearR, spec, nearR.toString(16) + " (>=r)", Result.ExpectedValue.FAILURE);
+ } else {
+ rTests[i++] = ecdhTest(ecpub, nearR, spec, nearR.toString(16) + " (<r)", Result.ExpectedValue.SUCCESS);
+ }
+ }
+ Test rTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near r.", rTests);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test private key values near zero, near p and near/larger than the order.", generateSuccess, zeroTest, pTest, rTest));
+ }
+
+ private Test ecdhTest(ECPublicKey pub, BigInteger SParam, ECParameterSpec spec, String desc, Result.ExpectedValue expect) throws NoSuchAlgorithmException {
+ ECPrivateKey priv = new RawECPrivateKey(SParam, spec);
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, priv, pub);
+ return CompoundTest.all(Result.ExpectedValue.SUCCESS, desc, KeyAgreementTest.expectError(testable, expect));
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java
new file mode 100644
index 0000000..ace8945
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneInvalidSuite.java
@@ -0,0 +1,120 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTest;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTest;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneInvalidSuite extends StandaloneTestSuite {
+ public StandaloneInvalidSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "invalid", "The invalid curve suite tests whether the library rejects points outside of the curve during ECDH.",
+ "Supports options:", "\t - gt/kpg-type", "\t - kt/ka-type (select multiple types by separating them with commas)");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ List<String> kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "invalid");
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+ ECParameterSpec spec = curve.toSpec();
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+
+ Test generateSuccess;
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp != null) {
+ generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ } else { //If KeyPair generation fails, try generating it on a default curve instead. Use this key only if it has the same domain parameters as our public key.
+ KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits());
+ Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY);
+ runTest(generateOnDefaultCurve);
+ kp = kgtOnDefaultCurve.getKeyPair();
+ if(kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) {
+ generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generateOnDefaultCurve);
+ } else {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", generateFail));
+ continue;
+ }
+ }
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+
+ List<Test> allKaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ List<Test> specificKaTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ ECPublicKey ecpub = ECUtil.toPublicKey(pub);
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ Test keyAgreement = KeyAgreementTest.expectError(testable, Result.ExpectedValue.FAILURE);
+ specificKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " invalid key test.", keyAgreement));
+ }
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with invalid public points.", specificKaTests.toArray(new Test[0])));
+ }
+ }
+ if(allKaTests.isEmpty()) {
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library."));
+ }
+ Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0]));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", generateSuccess, tests));
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneMiscSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneMiscSuite.java
new file mode 100644
index 0000000..f3a10eb
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneMiscSuite.java
@@ -0,0 +1,150 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import cz.crcs.ectester.standalone.test.base.*;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.util.*;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneMiscSuite extends StandaloneTestSuite {
+ private String kpgAlgo;
+ private String kaAlgo;
+ private String sigAlgo;
+ private List<String> kaTypes;
+ private List<String> sigTypes;
+
+ public StandaloneMiscSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "miscellaneous", "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves,",
+ "Barreto-Naehrig curves with small embedding degree and CM discriminant, MNT curves,",
+ "some Montgomery curves transformed to short Weierstrass form and Curve25519 transformed to short Weierstrass form.",
+ "Supports options:",
+ "\t - gt/kpg-type",
+ "\t - kt/ka-type (select multiple types by separating them with commas)",
+ "\t - st/sig-type (select multiple types by separating them with commas)");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ kpgAlgo = cli.getOptionValue("test.kpg-type");
+ kaAlgo = cli.getOptionValue("test.ka-type");
+ sigAlgo = cli.getOptionValue("test.sig-type");
+
+ kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+ sigTypes = sigAlgo != null ? Arrays.asList(sigAlgo.split(",")) : new ArrayList<>();
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+
+ Map<String, EC_Curve> anCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "anomalous");
+ Map<String, EC_Curve> ssCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "supersingular");
+ Map<String, EC_Curve> bnCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "Barreto-Naehrig");
+ Map<String, EC_Curve> mntCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "MNT");
+ List<EC_Curve> mCurves = new ArrayList<>();
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-221"));
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-383"));
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-511"));
+ EC_Curve curve25519 = EC_Store.getInstance().getObject(EC_Curve.class, "other", "Curve25519");
+
+ testCurves(anCurves.values(), "anomalous", kpg, Result.ExpectedValue.FAILURE);
+ testCurves(ssCurves.values(), "supersingular", kpg, Result.ExpectedValue.FAILURE);
+ testCurves(bnCurves.values(), "Barreto-Naehrig", kpg, Result.ExpectedValue.SUCCESS);
+ testCurves(mntCurves.values(), "MNT", kpg, Result.ExpectedValue.SUCCESS);
+ testCurves(mCurves, "Montgomery", kpg, Result.ExpectedValue.SUCCESS);
+ testCurve(curve25519, "Montgomery", kpg, Result.ExpectedValue.SUCCESS);
+ }
+
+ private void testCurve(EC_Curve curve, String catName, KeyPairGenerator kpg, Result.ExpectedValue expected) throws NoSuchAlgorithmException {
+ //generate KeyPair
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, curve.toSpec());
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp == null) {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() +
+ ". " + " Other tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", generateFail));
+ return;
+ }
+ Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+ ECPublicKey ecpub = (ECPublicKey) kp.getPublic();
+
+ //perform KeyAgreement tests
+ List<Test> kaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ kaTests.add(KeyAgreementTest.expectError(testable, expected));
+ }
+ }
+ if(kaTests.isEmpty()) {
+ kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified KeyAgreement types is supported by the library."));
+ }
+
+ //perform Signature tests
+ List<Test> sigTests = new LinkedList<>();
+ for (SignatureIdent sigIdent : cfg.selected.getSigs()) {
+ if (sigAlgo == null || sigIdent.containsAny(sigTypes)) {
+ Signature sig = sigIdent.getInstance(cfg.selected.getProvider());
+ SignatureTestable testable = new SignatureTestable(sig, ecpriv, ecpub, null);
+ sigTests.add(SignatureTest.expectError(testable, expected));
+ }
+ }
+ if(sigTests.isEmpty()) {
+ sigTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library."));
+ }
+
+ Test performKeyAgreements = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform specified KeyAgreements.", kaTests.toArray(new Test[0]));
+ Test performSignatures = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform specified Signatures.", sigTests.toArray(new Test[0]));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", generateSuccess, performKeyAgreements, performSignatures));
+ }
+
+ private void testCurves(Collection<EC_Curve> curves, String catName, KeyPairGenerator kpg, Result.ExpectedValue expected) throws NoSuchAlgorithmException {
+ for (EC_Curve curve : curves) {
+ testCurve(curve, catName, kpg, expected);
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java
new file mode 100644
index 0000000..dd50862
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java
@@ -0,0 +1,142 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import cz.crcs.ectester.standalone.test.base.*;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author David Hofman
+ */
+public class StandalonePerformanceSuite extends StandaloneTestSuite {
+ private final int count = 100;
+
+ public StandalonePerformanceSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "performance", "The performance test suite measures performance of KeyPair generation, KeyAgreement and Signature operations.",
+ "Supports options:",
+ "\t - gt/kpg-type (select multiple types by separating them with commas)",
+ "\t - kt/ka-type (select multiple types by separating them with commas)",
+ "\t - st/sig-type (select multiple types by separating them with commas)",
+ "\t - key-type");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ String sigAlgo = cli.getOptionValue("test.sig-type");
+ String keyAlgo = cli.getOptionValue("test.key-type", "AES");
+
+ List<String> kpgTypes = kpgAlgo != null ? Arrays.asList(kpgAlgo.split(",")) : new ArrayList<>();
+ List<String> kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+ List<String> sigTypes = sigAlgo != null ? Arrays.asList(sigAlgo.split(",")) : new ArrayList<>();
+
+ List<KeyPairGeneratorIdent> kpgIdents = new LinkedList<>();
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdents.add(kpgIdentOpt.get());
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ kpgIdents = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.containsAny(kpgTypes)).collect(Collectors.toList());
+ if (kpgIdents.isEmpty()) {
+ System.err.println("No KeyPairGenerator algorithms of specified types were found.");
+ return;
+ }
+ }
+
+ KeyGeneratorTestable kgtOne = null;
+ KeyGeneratorTestable kgtOther = null;
+ ECParameterSpec spec = null;
+ List<Test> kpgTests = new LinkedList<>();
+ for(KeyPairGeneratorIdent kpgIdent : kpgIdents) {
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+ if (cli.hasOption("test.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("test.bits"));
+ kgtOne = new KeyGeneratorTestable(kpg, bits);
+ kgtOther = new KeyGeneratorTestable(kpg, bits);
+ } else if (cli.hasOption("test.named-curve")) {
+ String curveName = cli.getOptionValue("test.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ spec = curve.toSpec();
+ kgtOne = new KeyGeneratorTestable(kpg, spec);
+ kgtOther = new KeyGeneratorTestable(kpg, spec);
+ } else {
+ kgtOne = new KeyGeneratorTestable(kpg);
+ kgtOther = new KeyGeneratorTestable(kpg);
+ }
+ kpgTests.add(PerformanceTest.repeat(kgtOne, kpgIdent.getName(), count));
+ }
+ runTest(KeyGeneratorTest.expect(kgtOther, Result.ExpectedValue.SUCCESS));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPairGenerator performance tests", kpgTests.toArray(new Test[0])));
+
+ List<Test> kaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable;
+ if (kaIdent.requiresKeyAlgo()) {
+ testable = new KeyAgreementTestable(ka, kgtOne, kgtOther, spec, keyAlgo);
+ } else {
+ testable = new KeyAgreementTestable(ka, kgtOne, kgtOther, spec);
+ }
+ kaTests.add(PerformanceTest.repeat(testable, kaIdent.getName(), count));
+ }
+ }
+ if(kaTests.isEmpty()) {
+ kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified KeyAgreement types is supported by the library."));
+ }
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement performance tests", kaTests.toArray(new Test[0])));
+
+ List<Test> sigTests = new LinkedList<>();
+ List<Test> sigTestsNoVerification = new LinkedList<>();
+ for (SignatureIdent sigIdent : cfg.selected.getSigs()) {
+ if (sigAlgo == null || sigIdent.containsAny(sigTypes)) {
+ Signature sig = sigIdent.getInstance(cfg.selected.getProvider());
+ sigTests.add(PerformanceTest.repeat(new SignatureTestable(sig, kgtOne, null), sigIdent.getName(),count));
+ if(kgtOne.getKeyPair() != null) {
+ ECPrivateKey signKey = (ECPrivateKey) kgtOne.getKeyPair().getPrivate();
+ sigTestsNoVerification.add(PerformanceTest.repeat(new SignatureTestable(sig, signKey, null, null), sigIdent.getName(), count));
+ }
+ }
+ }
+ if(sigTestsNoVerification.isEmpty() & !sigTests.isEmpty()) {
+ sigTestsNoVerification.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Signature tests with no verification require a successfully generated private key."));
+ }
+ if(sigTests.isEmpty()) {
+ sigTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library."));
+ sigTestsNoVerification.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library."));
+ }
+ Test signAndVerify = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Sign and verify", sigTests.toArray(new Test[0]));
+ Test signOnly = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Sign only, no verification", sigTestsNoVerification.toArray(new Test[0]));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Signature performance tests", signAndVerify, signOnly));
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java
new file mode 100644
index 0000000..94e810e
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneSignatureSuite.java
@@ -0,0 +1,87 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.ec.EC_SigResult;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import cz.crcs.ectester.standalone.test.base.SignatureTest;
+import cz.crcs.ectester.standalone.test.base.SignatureTestable;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.interfaces.ECPublicKey;
+import java.util.*;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneSignatureSuite extends StandaloneTestSuite {
+ public StandaloneSignatureSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "signature", "The signature test suite tests verifying various malformed and well-formed but invalid ECDSA signatures.",
+ "Supports options:", "\t - st/sig-type");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String sigAlgo = cli.getOptionValue("test.sig-type");
+
+ SignatureIdent sigIdent;
+ if (sigAlgo == null) {
+ // try ECDSA, if not, fail with: need to specify sig algo.
+ Optional<SignatureIdent> sigIdentOpt = cfg.selected.getSigs().stream()
+ .filter((ident) -> ident.contains("ECDSA"))
+ .findFirst();
+ if (sigIdentOpt.isPresent()) {
+ sigIdent = sigIdentOpt.get();
+ } else {
+ System.err.println("The default Signature algorithm type of \"ECDSA\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong sig algo/not found.
+ Optional<SignatureIdent> sigIdentOpt = cfg.selected.getSigs().stream()
+ .filter((ident) -> ident.contains(sigAlgo))
+ .findFirst();
+ if (sigIdentOpt.isPresent()) {
+ sigIdent = sigIdentOpt.get();
+ } else {
+ System.err.println("The Signature algorithm type of \"" + sigAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ Map<String, EC_SigResult> results = EC_Store.getInstance().getObjects(EC_SigResult.class, "wrong");
+ Map<String, List<EC_SigResult>> groups = EC_Store.mapToPrefix(results.values());
+
+ List<EC_SigResult> nok = groups.entrySet().stream().filter((e) -> e.getKey().equals("nok")).findFirst().get().getValue();
+
+ byte[] data = "Some stuff that is not the actual data".getBytes();
+ for (EC_SigResult sig : nok) {
+ ecdsaTest(sig, sigIdent, Result.ExpectedValue.FAILURE, data);
+ }
+
+ List<EC_SigResult> ok = groups.entrySet().stream().filter((e) -> e.getKey().equals("ok")).findFirst().get().getValue();
+ for (EC_SigResult sig : ok) {
+ ecdsaTest(sig, sigIdent, Result.ExpectedValue.SUCCESS, null);
+ }
+ }
+
+ private void ecdsaTest(EC_SigResult sig, SignatureIdent sigIdent, Result.ExpectedValue expected, byte[] defaultData) throws NoSuchAlgorithmException {
+ ECPublicKey ecpub = ECUtil.toPublicKey(EC_Store.getInstance().getObject(EC_Key.Public.class, sig.getVerifyKey()));
+
+ byte[] data = sig.getSigData();
+ if (data == null) {
+ data = defaultData;
+ }
+
+ Signature signature = sigIdent.getInstance(cfg.selected.getProvider());
+ SignatureTestable testable = new SignatureTestable(signature, ecpub, data, sig.getData(0));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "ECDSA test of " + sig.getId() + ".", SignatureTest.expectError(testable, expected)));
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java
new file mode 100644
index 0000000..e4e0013
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestSuite.java
@@ -0,0 +1,25 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.TestSuite;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.libs.ProviderECLibrary;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public abstract class StandaloneTestSuite extends TestSuite {
+ TreeCommandLine cli;
+ ECTesterStandalone.Config cfg;
+
+ public StandaloneTestSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli, String name, String... description) {
+ super(writer, name, description);
+ this.cfg = cfg;
+ this.cli = cli;
+ }
+
+ public ProviderECLibrary getLibrary() {
+ return cfg.selected;
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java
new file mode 100644
index 0000000..1e1889c
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTestVectorSuite.java
@@ -0,0 +1,63 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.*;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTest;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+
+import javax.crypto.KeyAgreement;
+import java.io.IOException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.util.Map;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneTestVectorSuite extends StandaloneTestSuite {
+
+ public StandaloneTestVectorSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "test-vectors", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "test");
+ for (EC_KAResult result : results.values()) {
+ if(!"DH_PLAIN".equals(result.getKA())) {
+ continue;
+ }
+
+ EC_Params onekey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOneKey());
+ if (onekey == null) {
+ onekey = EC_Store.getInstance().getObject(EC_Key.Private.class, result.getOneKey());
+ }
+ EC_Params otherkey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOtherKey());
+ if (otherkey == null) {
+ otherkey = EC_Store.getInstance().getObject(EC_Key.Public.class, result.getOtherKey());
+ }
+ if (onekey == null || otherkey == null) {
+ throw new IOException("Test vector keys couldn't be located.");
+ }
+
+ ECPrivateKey privkey = onekey instanceof EC_Keypair ?
+ (ECPrivateKey) ECUtil.toKeyPair((EC_Keypair) onekey).getPrivate() :
+ ECUtil.toPrivateKey((EC_Key.Private) onekey);
+ ECPublicKey pubkey = otherkey instanceof EC_Keypair ?
+ (ECPublicKey) ECUtil.toKeyPair((EC_Keypair) otherkey).getPublic() :
+ ECUtil.toPublicKey((EC_Key.Public) otherkey);
+
+ KeyAgreementIdent kaIdent = KeyAgreementIdent.get("ECDH");
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, privkey, pubkey);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test vector " + result.getId(), KeyAgreementTest.match(testable, result.getData(0))));
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java
new file mode 100644
index 0000000..f182952
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneTwistSuite.java
@@ -0,0 +1,120 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTest;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTest;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneTwistSuite extends StandaloneTestSuite {
+ public StandaloneTwistSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "twist", "The twist test suite tests whether the library correctly rejects points on the quadratic twist of the curve during ECDH.",
+ "Supports options:", "\t - gt/kpg-type", "\t - kt/ka-type (select multiple types by separating them with commas)");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ List<String> kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "twist");
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
+ EC_Curve curve = e.getKey();
+ List<EC_Key.Public> keys = e.getValue();
+
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+ ECParameterSpec spec = curve.toSpec();
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+
+ Test generateSuccess;
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp != null) {
+ generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ } else { //If KeyPair generation fails, try generating it on a default curve instead. Use this key only if it has the same domain parameters as our public key.
+ KeyGeneratorTestable kgtOnDefaultCurve = new KeyGeneratorTestable(kpg, curve.getBits());
+ Test generateOnDefaultCurve = KeyGeneratorTest.expectError(kgtOnDefaultCurve, Result.ExpectedValue.ANY);
+ runTest(generateOnDefaultCurve);
+ kp = kgtOnDefaultCurve.getKeyPair();
+ if(kp != null && ECUtil.equalKeyPairParameters((ECPrivateKey) kp.getPrivate(), ECUtil.toPublicKey(keys.get(0)))) {
+ generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generateOnDefaultCurve);
+ } else {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ". " + "KeyAgreement tests will be skipped.", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", generateFail));
+ continue;
+ }
+ }
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+
+ List<Test> allKaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ List<Test> specificKaTests = new LinkedList<>();
+ for (EC_Key.Public pub : keys) {
+ ECPublicKey ecpub = ECUtil.toPublicKey(pub);
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ Test keyAgreement = KeyAgreementTest.expectError(testable, Result.ExpectedValue.FAILURE);
+ specificKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " twist key test.", keyAgreement));
+ }
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform " + kaIdent.getName() + " with public points on twist.", specificKaTests.toArray(new Test[0])));
+ }
+ }
+ if(allKaTests.isEmpty()) {
+ allKaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified key agreement types is supported by the library."));
+ }
+ Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", allKaTests.toArray(new Test[0]));
+ doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", generateSuccess, tests));
+ }
+ }
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java
new file mode 100644
index 0000000..a457a33
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/test/suites/StandaloneWrongSuite.java
@@ -0,0 +1,343 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.*;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTest;
+import cz.crcs.ectester.standalone.test.base.KeyAgreementTestable;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTest;
+import cz.crcs.ectester.standalone.test.base.KeyGeneratorTestable;
+
+import javax.crypto.KeyAgreement;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.*;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author David Hofman
+ */
+public class StandaloneWrongSuite extends StandaloneTestSuite {
+ private KeyAgreementIdent kaIdent;
+ private KeyPairGenerator kpg;
+
+ public StandaloneWrongSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "wrong", "The wrong curve suite tests whether the library rejects domain parameters which are not curves.",
+ "Supports options:",
+ "\t - gt/kpg-type",
+ "\t - kt/ka-type",
+ "\t - skip (place this option before the library name to skip tests that can potentially cause a freeze)");
+ }
+
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ boolean skip = cli.getArg(1).equalsIgnoreCase("-skip");
+
+ KeyPairGeneratorIdent kpgIdent;
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains(kpgAlgo))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdent = kpgIdentOpt.get();
+ } else {
+ System.err.println("The KeyPairGenerator algorithm type of \"" + kpgAlgo + "\" was not found.");
+ return;
+ }
+ }
+ kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+
+ if (kaAlgo == null) {
+ // try ECDH, if not, fail with: need to specify ka algo.
+ Optional<KeyAgreementIdent> kaIdentOpt = cfg.selected.getKAs().stream()
+ .filter((ident) -> ident.contains("ECDH"))
+ .findFirst();
+ if (kaIdentOpt.isPresent()) {
+ kaIdent = kaIdentOpt.get();
+ } else {
+ System.err.println("The default KeyAgreement algorithm type of \"ECDH\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong ka algo/not found.
+ Optional<KeyAgreementIdent> kaIdentOpt = cfg.selected.getKAs().stream()
+ .filter((ident) -> ident.contains(kaAlgo))
+ .findFirst();
+ if (kaIdentOpt.isPresent()) {
+ kaIdent = kaIdentOpt.get();
+ } else {
+ System.err.println("The KeyAgreement algorithm type of \"" + kaAlgo + "\" was not found.");
+ return;
+ }
+ }
+
+ /* Just do the default run on the wrong curves.
+ * These should generally fail, the curves aren't curves.
+ */
+ if(!skip) {
+ Map<String, EC_Curve> wrongCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "wrong");
+ for (Map.Entry<String, EC_Curve> e : wrongCurves.entrySet()) {
+
+ EC_Curve curve = e.getValue();
+ ECParameterSpec spec = curve.toSpec();
+ String type = curve.getField() == javacard.security.KeyPair.ALG_EC_FP ? "FP" : "F2M";
+
+ //try generating a keypair
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.ANY);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if (kp == null) {
+ Test generateFail = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generating KeyPair has failed on " + curve.getId() + ".", generate);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Wrong curve test of " + curve.getBits()
+ + "b " + type + ". " + curve.getDesc(), generateFail));
+ continue;
+ }
+ Test generateSuccess = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Generate keypair.", generate);
+ ECPrivateKey ecpriv = (ECPrivateKey) kp.getPrivate();
+ ECPublicKey ecpub = (ECPublicKey) kp.getPublic();
+
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, ecpriv, ecpub);
+ Test ecdh = KeyAgreementTest.expectError(testable, Result.ExpectedValue.FAILURE);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Wrong curve test of " + curve.getBits()
+ + "b " + type + ". " + curve.getDesc(), generateSuccess, ecdh));
+ }
+ }
+
+ /*
+ * Do some interesting tests with corrupting the custom curves.
+ * For prime field:
+ * - p = 0
+ * - p = 1
+ * - p is a square of a prime
+ * - p is a composite q * s with q, s primes
+ * - TODO: p divides discriminant
+ */
+ Map<String, EC_Curve> curveMap = EC_Store.getInstance().getObjects(EC_Curve.class, "secg");
+ List<EC_Curve> curves = curveMap.entrySet().stream().filter((e) -> e.getKey().endsWith("r1") &&
+ e.getValue().getField() == javacard.security.KeyPair.ALG_EC_FP).map(Map.Entry::getValue).collect(Collectors.toList());
+ Random r = new Random();
+ for (EC_Curve curve : curves) {
+ short bits = curve.getBits();
+ final byte[] originalp = curve.getParam(EC_Consts.PARAMETER_FP)[0];
+
+ curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{ ByteUtil.hexToBytes("0")});
+ Test prime0 = ecdhTest(toCustomSpec(curve),"ECDH with p = 0.");
+
+ curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{ ByteUtil.hexToBytes("1")});
+ Test prime1 = ecdhTest(toCustomSpec(curve),"ECDH with p = 1.");
+
+ short keyHalf = (short) (bits / 2);
+ BigInteger prime = new BigInteger(keyHalf, 50, r);
+ BigInteger primePow = prime.pow(2);
+ byte[] primePowBytes = ECUtil.toByteArray(primePow, bits);
+ curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{primePowBytes});
+
+ Test primePower = ecdhTest(toCustomSpec(curve), "ECDH with p = q^2.");
+
+ BigInteger q = new BigInteger(keyHalf, r);
+ BigInteger s = new BigInteger(keyHalf, r);
+ BigInteger compositeValue = q.multiply(s);
+ byte[] compositeBytes = ECUtil.toByteArray(compositeValue, bits);
+ curve.setParam(EC_Consts.PARAMETER_FP, new byte[][]{compositeBytes});
+
+ Test composite = ecdhTest(toCustomSpec(curve), "ECDH with p = q * s.");
+
+ Test wrongPrime = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0 , prime1, primePower, composite );
+
+ curve.setParam(EC_Consts.PARAMETER_FP, new byte[][] {originalp});
+ final byte[][] originalG = curve.getParam(EC_Consts.PARAMETER_G);
+
+ byte[] Gx = new BigInteger(curve.getBits(), r).toByteArray();
+ byte[] Gy = new BigInteger(curve.getBits(), r).toByteArray();
+ curve.setParam(EC_Consts.PARAMETER_G, new byte[][] {Gx, Gy});
+ Test fullRandomG = ecdhTest(toCustomSpec(curve), "ECDH with G = random data.");
+
+ final BigInteger originalBigp = new BigInteger(1, originalp);
+ byte[] smallerGx = new BigInteger(curve.getBits(), r).mod(originalBigp).toByteArray();
+ byte[] smallerGy = new BigInteger(curve.getBits(), r).mod(originalBigp).toByteArray();
+ curve.setParam(EC_Consts.PARAMETER_G, new byte[][] {smallerGx, smallerGy});
+ Test randomG = ecdhTest(toCustomSpec(curve), "ECDH with G = random data mod p.");
+
+ curve.setParam(EC_Consts.PARAMETER_G, new byte[][] {ByteUtil.hexToBytes("0"), ByteUtil.hexToBytes("0")});
+ Test zeroG = ecdhTest(toCustomSpec(curve), "ECDH with G = infinity.");
+
+ Test wrongG = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted G parameter.", fullRandomG, randomG, zeroG);
+
+ curve.setParam(EC_Consts.PARAMETER_G, originalG);
+ final byte[] originalR = curve.getParam(EC_Consts.PARAMETER_R)[0];
+ final BigInteger originalBigR = new BigInteger(1, originalR);
+
+ List<Test> allRTests = new LinkedList<>();
+ if(!skip) {
+ byte[] RZero = new byte[]{(byte) 0};
+ curve.setParam(EC_Consts.PARAMETER_R, new byte[][]{RZero});
+ allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = 0."));
+
+
+ byte[] ROne = new byte[]{(byte) 1};
+ curve.setParam(EC_Consts.PARAMETER_R, new byte[][]{ROne});
+ allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = 1."));
+ }
+
+ BigInteger prevPrimeR;
+ do {
+ prevPrimeR = BigInteger.probablePrime(originalBigR.bitLength() - 1, r);
+ } while (prevPrimeR.compareTo(originalBigR) >= 0);
+ byte[] prevRBytes = ECUtil.toByteArray(prevPrimeR, bits);
+ curve.setParam(EC_Consts.PARAMETER_R, new byte[][] {prevRBytes});
+ allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = some prime (but [r]G != infinity) smaller than original R."));
+
+ BigInteger nextPrimeR = originalBigR.nextProbablePrime();
+ byte[] nextRBytes = ECUtil.toByteArray(nextPrimeR, bits);
+ curve.setParam(EC_Consts.PARAMETER_R, new byte[][]{nextRBytes});
+ allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = some prime (but [r]G != infinity) larger than original R."));
+
+ byte[] nonprimeRBytes = nextRBytes.clone();
+ nonprimeRBytes[nonprimeRBytes.length - 1] ^= 1;
+ curve.setParam(EC_Consts.PARAMETER_R, new byte[][] {nonprimeRBytes} );
+ allRTests.add(ecdhTest(toCustomSpec(curve), "ECDH with R = some composite (but [r]G != infinity)."));
+
+ Test wrongR = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", allRTests.toArray(new Test[0]));
+
+ curve.setParam(EC_Consts.PARAMETER_R, new byte[][] {originalR});
+
+ byte[] kRaw = new byte[]{(byte) 0xff};
+ curve.setParam(EC_Consts.PARAMETER_K, new byte[][] {kRaw});
+ Test bigK = ecdhTest(toCustomSpec(curve), "ECDH with big K.");
+
+ byte[] kZero = new byte[]{(byte) 0};
+ curve.setParam(EC_Consts.PARAMETER_K, new byte[][]{kZero});
+ Test zeroK = ecdhTest(toCustomSpec(curve), "ECDH with K = 0.");
+
+ Test wrongK = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted K parameter.", bigK, zeroK);
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of " + bits + "b " + "FP", wrongPrime, wrongG, wrongR , wrongK));
+ }
+
+
+ /*
+ * For binary field:
+ * - e1 = e2 = e3 = 0
+ * - e1, e2 or e3 is larger than m.
+ */
+ curveMap = EC_Store.getInstance().getObjects(EC_Curve.class, "secg");
+ curves = curveMap.entrySet().stream().filter((e) -> e.getKey().endsWith("r1") &&
+ e.getValue().getField() == EC_Consts.ALG_EC_F2M).map(Map.Entry::getValue).collect(Collectors.toList());
+ for (EC_Curve curve : curves) {
+ short bits = curve.getBits();
+ byte[][] coeffBytes;
+
+
+ coeffBytes = new byte[][]{
+ ByteUtil.shortToBytes(bits),
+ ByteUtil.shortToBytes((short) 0),
+ ByteUtil.shortToBytes((short) 0),
+ ByteUtil.shortToBytes((short) 0)};
+ curve.setParam(EC_Consts.PARAMETER_F2M, coeffBytes);
+ Test coeff0 = ecdhTest(toCustomSpec(curve), "ECDH with wrong field polynomial: x^");
+
+ short e1 = (short) (2 * bits);
+ short e2 = (short) (3 * bits);
+ short e3 = (short) (4 * bits);
+ coeffBytes = new byte[][]{
+ ByteUtil.shortToBytes(bits),
+ ByteUtil.shortToBytes(e1),
+ ByteUtil.shortToBytes(e2),
+ ByteUtil.shortToBytes(e3)};
+ curve.setParam(EC_Consts.PARAMETER_F2M, coeffBytes);
+ Test coeffLarger = ecdhTest(toCustomSpec(curve), "ECDH with wrong field poly, powers larger than " + bits);
+
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with corrupted field polynomial parameter over " + curve.getBits() + "b F2M", coeff0, coeffLarger));
+ }
+ }
+
+ private Test ecdhTest(ECParameterSpec spec, String desc) throws NoSuchAlgorithmException {
+ //generate KeyPair
+ KeyGeneratorTestable kgt = new KeyGeneratorTestable(kpg, spec);
+ Test generate = KeyGeneratorTest.expectError(kgt, Result.ExpectedValue.FAILURE);
+ runTest(generate);
+ KeyPair kp = kgt.getKeyPair();
+ if(kp == null) {
+ return CompoundTest.all(Result.ExpectedValue.SUCCESS, desc, generate);
+ }
+ ECPublicKey pub = (ECPublicKey) kp.getPublic();
+ ECPrivateKey priv = (ECPrivateKey) kp.getPrivate();
+
+ //perform ECDH
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable = new KeyAgreementTestable(ka, priv, pub);
+ Test ecdh = KeyAgreementTest.expect(testable, Result.ExpectedValue.FAILURE);
+ return CompoundTest.all(Result.ExpectedValue.SUCCESS, desc, generate, ecdh);
+ }
+
+ //constructs EllipticCurve from EC_Curve even if the parameters of the curve are wrong
+ private EllipticCurve toCustomCurve(EC_Curve curve) {
+ ECField field;
+ if (curve.getField() == javacard.security.KeyPair.ALG_EC_FP) {
+ field = new CustomECFieldFp(new BigInteger(1, curve.getData(0)));
+ } else {
+ byte[][] fieldData = curve.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 CustomECFieldF2m(m, powers);
+ }
+
+ BigInteger a = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_A)[0]);
+ BigInteger b = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_B)[0]);
+
+ return new CustomEllipticCurve(field, a, b);
+ }
+
+ //constructs ECParameterSpec from EC_Curve even if the parameters of the curve are wrong
+ private ECParameterSpec toCustomSpec(EC_Curve curve) {
+ EllipticCurve customCurve = toCustomCurve(curve);
+
+ byte[][] G = curve.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, curve.getParam(EC_Consts.PARAMETER_R)[0]);
+
+ int h = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_K)[0]).intValue();
+ return new CustomECParameterSpec(customCurve, generator, n, h);
+ }
+}