aboutsummaryrefslogtreecommitdiff
path: root/standalone
diff options
context:
space:
mode:
authorJ08nY2024-03-22 23:58:55 +0100
committerJ08nY2024-03-25 14:52:43 +0100
commit73af477a8774e1ede5dd8de6491eb353dc0b12bd (patch)
tree2d4e3b19bc5fb55308b886032312be76341736d4 /standalone
parent64b95fa059295e1dc23371c849f2302c1c18f5b4 (diff)
downloadECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.tar.gz
ECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.tar.zst
ECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.zip
Diffstat (limited to 'standalone')
-rw-r--r--standalone/build.gradle.kts23
-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.java126
-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.java81
-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/.clang-format90
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/.gitignore8
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile217
-rwxr-xr-xstandalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile.bat163
-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/libs/jni/boringssl.c516
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/botan.cpp528
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.c254
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.h44
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.c252
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.h68
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp115
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp50
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp767
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/gcrypt.c623
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/ippcp.c698
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/libressl.c609
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/matrixssl.c397
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mbedtls.c544
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mscng.c1273
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/native.h2044
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/nettle.c511
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/openssl.c584
-rw-r--r--standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c465
-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
77 files changed, 17654 insertions, 0 deletions
diff --git a/standalone/build.gradle.kts b/standalone/build.gradle.kts
new file mode 100644
index 0000000..53a306c
--- /dev/null
+++ b/standalone/build.gradle.kts
@@ -0,0 +1,23 @@
+plugins {
+ application
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation(files("$rootDir/ext/wolfcrypt-jni.jar"))
+ implementation(project(":common"))
+}
+
+application {
+ mainClass = "cz.crcs.ectester.standalone.ECTesterStandalone"
+}
+
+tasks.withType<JavaCompile> {
+ options.compilerArgs.addAll(arrayOf(
+ "--add-modules", "jdk.crypto.ec",
+ "--add-exports", "jdk.crypto.ec/sun.security.ec=ALL-UNNAMED"
+ ))
+} \ No newline at end of file
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..9b912cb
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
@@ -0,0 +1,126 @@
+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);
+ }
+ }
+ }
+ }
+
+ 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..db85b02
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
@@ -0,0 +1,81 @@
+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. */
+ FileUtil.writeNewer(ECTesterStandalone.LIB_RESOURCE_DIR + resource + "." + suffix, libPath);
+
+ /* 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);
+ FileUtil.writeNewer(ECTesterStandalone.LIB_RESOURCE_DIR + requirement, reqPath);
+ System.load(reqPath.toString());
+ } else {
+ System.loadLibrary(requirement);
+ }
+ }
+ } catch (UnsatisfiedLinkError ule) {
+ return false;
+ }
+
+ System.load(libPath.toString());
+
+ provider = createProvider();
+ return super.initialize();
+ } catch (IOException | UnsatisfiedLinkError ignored) {
+ }
+ 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/.clang-format b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/.clang-format
new file mode 100644
index 0000000..0aa8562
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/.clang-format
@@ -0,0 +1,90 @@
+---
+Language: Cpp
+# BasedOnStyle: Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: true
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Attach
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 140
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^<.*\.h>'
+ Priority: 1
+ - Regex: '^<.*'
+ Priority: 2
+ - Regex: '.*'
+ Priority: 3
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 10000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Auto
+TabWidth: 4
+UseTab: ForIndentation
+...
+
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/.gitignore b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/.gitignore
new file mode 100644
index 0000000..777d8e0
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/.gitignore
@@ -0,0 +1,8 @@
+libcore_s.a
+libcrypt_s.a
+matrixssl/
+*.o
+*.so
+
+CMakeLists.txt
+cmake-build-debug \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile
new file mode 100644
index 0000000..c3995e3
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile
@@ -0,0 +1,217 @@
+###############################################################################
+## General CC setup.
+
+CC?=gcc
+CXX?=g++
+
+LFLAGS+=-fPIC -shared
+CFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
+CXXFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
+
+DEBUG ?= 0
+
+ifeq ($(DEBUG), 1)
+ CFLAGS+=-g -Wall
+ LFLAGS+=-g
+ CXXFLAGS+=-g -Wall
+else
+ CFLAGS+=-O2
+ LFLAGS+=-O2
+ CXXFLAGS+=-O2
+endif
+
+###############################################################################
+## Java JNI setup.
+
+ifeq ($(JAVA_HOME),)
+ ifeq ($(OS),Windows_NT)
+ which = $(shell where $1)
+ else
+ which = $(shell which $1)
+ endif
+ JAVAC ?= $(realpath $(call which,javac))
+ JAVA_HOME = $(abspath $(dir $(JAVAC))..)
+endif
+
+ifneq ($(JAVA_HOME),)
+ JNI_INCLUDEDIR ?= $(JAVA_HOME)/include
+endif
+
+ifeq ($(JNI_INCLUDEDIR),)
+ $(error Could not determine JNI include dir. Try specifying either JAVA_HOME or JNI_INCLUDEDIR.)
+endif
+
+TARGETTRIPLET := $(shell $(CC) -dumpmachine)
+
+ifeq ($(JNI_PLATFORM),)
+ ifeq ($(findstring mingw,$(TARGETTRIPLET)),mingw)
+ JNI_PLATFORM:= win32
+ else
+ ifeq ($(findstring linux,$(TARGETTRIPLET)),linux)
+ JNI_PLATFORM:= linux
+ endif
+ endif
+endif
+
+JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)
+
+###############################################################################
+## Targets.
+
+all: tomcrypt botan cryptopp openssl boringssl gcrypt mbedtls ippcp matrixssl nettle libressl
+
+# Common utils
+c_utils.o: c_utils.c
+ $(CC) $(CFLAGS) -c $<
+
+lib_timing.so: c_timing.c
+ $(CC) -o $@ -shared $(CFLAGS) -Wl,-soname,lib_timing.so $<
+
+cpp_utils.o: cpp_utils.cpp
+ $(CXX) $(CXXFLAGS) -c $<
+
+
+# OpenSSL shim
+openssl: openssl_provider.so
+
+openssl_provider.so: openssl.o c_utils.o | lib_timing.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs openssl) -l:lib_timing.so
+
+openssl.o: openssl.c
+ $(CC) $(shell pkg-config --cflags openssl) $(CFLAGS) -c $<
+
+
+# BoringSSL shim
+boringssl: boringssl_provider.so
+
+lib_boringssl.so:
+ cp ../../../../../../../ext/boringssl/build/crypto/libcrypto.so lib_boringssl.so
+
+boringssl_provider.so: boringssl.o c_utils.o | lib_timing.so lib_boringssl.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_boringssl.so -l:lib_timing.so
+
+boringssl.o: boringssl.c
+ $(CC) -I../../../../../../../ext/boringssl/include/ $(CFLAGS) -c $<
+
+
+# libgcrypt shim
+gcrypt: gcrypt_provider.so
+
+gcrypt_provider.so: gcrypt.o c_utils.o | lib_timing.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell libgcrypt-config --libs) -l:lib_timing.so
+
+gcrypt.o: gcrypt.c
+ $(CC) $(shell libgcrypt-config --cflags) $(CFLAGS) -c $<
+
+
+# Libtomcrypt shim
+tomcrypt: tomcrypt_provider.so
+
+tomcrypt_provider.so: tomcrypt.o c_utils.o | lib_timing.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt) -l:lib_timing.so
+
+tomcrypt.o: tomcrypt.c
+ $(CC) -DLTM_DESC $(shell pkg-config --cflags libtomcrypt) $(CFLAGS) -c $<
+
+
+# Botan-2 shim
+botan: botan_provider.so
+
+botan_provider.so: botan.o cpp_utils.o | lib_timing.so
+ $(CXX) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs botan-2) -l:lib_timing.so
+
+botan.o: botan.cpp
+ $(CXX) $(shell pkg-config --cflags botan-2) $(CXXFLAGS) -c $<
+
+
+# Crypto++ shim
+CRYPTOPP_NAME := "libcrypto++"
+ifeq ($(shell pkg-config --exists $(CRYPTOPP_NAME); echo $$?),1)
+ CRYPTOPP_NAME := "libcryptopp"
+endif
+cryptopp: cryptopp_provider.so
+
+cryptopp_provider.so: cryptopp.o cpp_utils.o | lib_timing.so
+ $(CXX) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs $(CRYPTOPP_NAME)) -l:lib_timing.so
+
+cryptopp.o: cryptopp.cpp
+ $(CXX) $(shell pkg-config --cflags $(CRYPTOPP_NAME)) $(CXXFLAGS) -c $<
+
+
+# mbedTLS shim
+mbedtls: mbedtls_provider.so
+
+mbedtls_provider.so: mbedtls.o c_utils.o | lib_timing.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. -lmbedcrypto -l:lib_timing.so
+
+mbedtls.o: mbedtls.c
+ $(CC) $(CFLAGS) -c $<
+
+
+# Intel Performance Primitives crypto shim
+ippcp: ippcp_provider.so
+
+lib_ippcp.so:
+ cp ../../../../../../../ext/ipp-crypto/build/.build/RELEASE/lib/libippcp.so lib_ippcp.so
+
+ippcp_provider.so: ippcp.o c_utils.o | lib_timing.so lib_ippcp.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_ippcp.so -l:lib_timing.so
+
+ippcp.o: ippcp.c
+ $(CC) -I../../../../../../../ext/ipp-crypto/build/.build/RELEASE/include/ $(CFLAGS) -c $<
+
+
+# MatrixSSL shim
+matrixssl: matrixssl_provider.so
+
+matrixssl_provider.so: matrixssl.o c_utils.o | lib_timing.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' -L. $^ libcrypt_s.a libcore_s.a -l:lib_timing.so
+
+matrixssl.o: matrixssl.c
+ $(CC) $(CFLAGS) -Imatrixssl/ -c $<
+
+
+# Nettle shim
+nettle: nettle_provider.so
+
+nettle_provider.so: nettle.o c_utils.o | lib_timing.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. $(shell pkg-config --libs nettle) -l:lib_timing.so $(shell pkg-config --libs hogweed) -lgmp
+
+nettle.o: nettle.c
+ $(CC) $(shell pkg-config --cflags nettle) $(shell pkg-config --libs hogweed) -lgmp $(CFLAGS) -c $<
+
+
+# LibreSSL shim
+libressl: libressl_provider.so
+
+lib_libressl.so:
+ cp ../../../../../../../ext/libressl/build/crypto/libcrypto.so lib_libressl.so
+
+libressl_provider.so: libressl.o c_utils.o | lib_timing.so lib_libressl.so
+ $(CC) $(LFLAGS) -o $@ -Wl,-rpath,'$$ORIGIN/lib' $^ -L. lib_libressl.so -l:lib_timing.so
+
+libressl.o: libressl.c
+ $(CC) -I../../../../../../../ext/libressl/include/ $(CFLAGS) -c $<
+
+
+help:
+ @echo "# This makefile builds the JNI shims necessary to test native libraries."
+ @echo "# Targets:"
+ @echo " - openssl"
+ @echo " - boringssl"
+ @echo " - gcrypt"
+ @echo " - tomcrypt"
+ @echo " - botan"
+ @echo " - cryptopp"
+ @echo " - mbedtls"
+ @echo " - ippcp"
+ @echo " - matrixssl"
+ @echo " - nettle"
+ @echo " - libressl"
+
+
+clean:
+ rm -rf *.o
+ rm -rf *.so
+
+.PHONY: all help clean openssl boringssl gcrypt tomcrypt botan cryptopp mbedtls ippcp matrixssl nettle libressl
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile.bat b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile.bat
new file mode 100755
index 0000000..e6c98d5
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/Makefile.bat
@@ -0,0 +1,163 @@
+@if not defined _echo echo off
+setlocal EnableDelayedExpansion
+
+:: ENV variables respected:
+:: - JAVA_HOME
+:: - CC
+:: - USE_EXT_MSCNG
+:: - DEBUG
+
+:: See if we are cleaning.
+if "%1" == "clean" (
+ echo ** cleaning
+ del *.dll *.exp *.lib *.obj
+ exit
+)
+
+set TAB=
+
+
+:: Determine arch.
+reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL 2>&1 && (set ARCH=32& set ARCH_S=x86& set ARCH_VS=x86) || (set ARCH=64& set ARCH_S=x64& set ARCH_VS=amd64)
+
+echo ** ARCH%TAB%%TAB%%ARCH_S%
+
+
+:: Find a working visual studio environment.
+set found=0
+set vsw_path="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
+
+set vs_path=
+for /f "usebackq delims=" %%i in (`%vsw_path% -nologo -prerelease -latest -property installationPath`) do (
+ if exist "%%i\Common7\Tools\vsdevcmd.bat" (
+ echo ** VsDevCmd%TAB%%TAB%%%i\Common7\Tools\vsdevcmd.bat
+ call "%%i\Common7\Tools\vsdevcmd.bat" -no_logo -arch=%ARCH_VS%
+ if ERRORLEVEL 1 (
+ echo nope.
+ ) else (
+ set found=1
+ set vs_path=%%i
+ break
+ )
+ )
+)
+
+:: Test if we have a visual studio env.
+if %found% EQU 0 (
+ echo Working VsDevCmd not found.
+ exit /b 2
+)
+
+echo ** VS_PATH%TAB%%TAB%%vs_path%
+
+
+:: Try to find vcruntime.
+set vc_base=%vs_path%\VC\Tools\MSVC\
+if exist %vc_base% (
+ set vc_version=
+ for /f "delims=" %%i in ('dir /b /on "!vc_base!"') do (
+ set vc_version=%%i
+ )
+ echo ** VC_VERSION%TAB%!vc_version!
+ set vc_include=%vc_base%!vc_version!\include
+ set vc_lib=%vc_base%!vc_version!\lib\%ARCH_S%
+)
+
+
+:: Get the paths to Microsoft CNG SDK.
+set root_rel=..\..\..\..\..\..\..\
+set mscng_rel_include=ext\mscng\10\Include
+set mscng_rel_lib=ext\mscng\10\Lib
+
+pushd %root_rel%
+pushd %mscng_rel_include%
+set mscng_include=%CD%
+popd
+pushd %mscng_rel_lib%
+set mscng_lib=%CD%
+popd
+popd
+
+set mscng_lib_arch=%mscng_lib%\X%ARCH%
+
+echo ** CNG_INCLUDE%TAB%%mscng_include%
+echo ** CNG_LIB%TAB%%TAB%%mscng_lib_arch%
+
+
+:: Get the paths to Java JNI.
+if not defined JAVA_HOME (
+ set jva=
+ for /f "delims=" %%i in ('where javac') do (
+ set jva=%%~dpi
+ )
+ pushd !jva!\..
+ set JAVA_HOME=!CD!
+ popd
+)
+
+echo ** JAVA_HOME%TAB%%JAVA_HOME%
+
+set JNI_INCLUDEDIR=%JAVA_HOME%\include
+set JNI_PLATFORMINCLUDEDIR=%JNI_INCLUDEDIR%\win32
+set JNI_LIBDIR=%JAVA_HOME%\lib
+
+
+:: Setup binaries.
+if not defined CC (
+ set CC=cl.exe
+)
+
+echo ** CC%TAB%%TAB%%CC%
+
+
+:: Try to find uCRT.
+set ucrt_base=%ProgramFiles(x86)%\Windows Kits\10\
+if exist %ucrt_base% (
+ set ucrt_version=
+ for /f "delims=" %%i in ('dir /b /on "!ucrt_base!\Include"') do (
+ set ucrt_version=%%i
+ )
+ echo ** uCRT%TAB%%TAB%!ucrt_version!
+ set ucrt_include=%ucrt_base%Include\!ucrt_version!\ucrt
+ set ucrt_lib=%ucrt_base%Lib\!ucrt_version!
+ set ucrt_lib_arch=!ucrt_lib!\ucrt\%ARCH_S%
+)
+
+
+:: Setup INCLUDE paths.
+set INCLUDE_CLI=/I. /I"%JNI_INCLUDEDIR%" /I"%JNI_PLATFORMINCLUDEDIR%"
+
+if defined USE_EXT_MSCNG (
+ set INCLUDE_CLI=!INCLUDE_CLI! /I"%mscng_include%"
+)
+
+echo ** INCLUDE%TAB%%TAB%%INCLUDE%
+echo ** INCLUDE_CLI%TAB%%INCLUDE_CLI%
+
+
+:: Setup LIB paths.
+set LIBPATH=/LIBPATH:"%JNI_LIBDIR%"
+
+if defined USE_EXT_MSCNG (
+ set LIBPATH=!LIBPATH! /LIBPATH:"%mscng_lib_arch%"
+)
+
+echo ** LIB%TAB%%TAB%%LIB%
+echo ** LIBPATH%TAB%%TAB%%LIBPATH%
+
+
+:: Setup DEBUB options.
+set OTHER_CLI=
+if defined DEBUG (
+ set OTHER_CLI=/Od /Z7
+) else (
+ set OTHER_CLI=/O2
+)
+
+echo ** OTHER_CLI%TAB%%OTHER_CLI%
+echo.
+
+echo ^>^> %CC% /W2 /EHsc %OTHER_CLI% %INCLUDE_CLI% mscng.c c_utils.c c_timing.c bcrypt.lib jvm.lib kernel32.lib /Femscng_provider.dll /LD /link %LIBPATH% /nologo
+echo.
+
+%CC% /W2 /EHsc %OTHER_CLI% %INCLUDE_CLI% mscng.c c_utils.c c_timing.c bcrypt.lib jvm.lib kernel32.lib /Femscng_provider.dll /LD /link %LIBPATH% /nologo
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/libs/jni/boringssl.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/boringssl.c
new file mode 100644
index 0000000..bca2ead
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/boringssl.c
@@ -0,0 +1,516 @@
+#include "native.h"
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/opensslv.h>
+#include <openssl/objects.h>
+#include <openssl/obj_mac.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Boringssl");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, OPENSSL_VERSION_TEXT);
+ long ver_hi = (OPENSSL_VERSION_NUMBER & 0xff000000L) >> 28;
+ long ver_mid = (OPENSSL_VERSION_NUMBER & 0xff0000L) >> 20;
+ long ver_low = (OPENSSL_VERSION_NUMBER & 0xff00L) >> 12;
+ double version = (double)ver_hi + ((double)ver_mid/10) + ((double)ver_low/100);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Boringssl_setup(JNIEnv *env, jobject self) {
+ ERR_load_crypto_strings();
+ CRYPTO_library_init();
+
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, self, "EC", "Boringssl");
+ ADD_KA(env, self, "ECDH", "BoringsslECDH");
+ ADD_SIG(env, self, "NONEwithECDSA", "BoringsslECDSAwithNONE");
+
+ init_classes(env, "Boringssl");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getCurves(JNIEnv *env, jobject self) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ jstring curve_name = (*env)->NewStringUTF(env, OBJ_nid2sn(curves[i].nid));
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_keysizeSupported(JNIEnv *env, jobject self, jint keysize) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ EC_GROUP *curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ EC_GROUP_free(curve);
+ return JNI_TRUE;
+ }
+ EC_GROUP_free(curve);
+ }
+ return JNI_FALSE;
+}
+
+static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ int size = BN_num_bytes(bn);
+ jbyteArray bytes = (*env)->NewByteArray(env, size);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ BN_bn2bin(bn, (unsigned char *) data);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) {
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
+ jsize byte_length = (*env)->GetArrayLength(env, byte_array);
+ jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL);
+ (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static EC_GROUP *create_curve(JNIEnv *env, jobject params) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return NULL;
+ }
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+ BIGNUM *a_bn = biginteger_to_bignum(env, a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+ BIGNUM *b_bn = biginteger_to_bignum(env, b);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+ BIGNUM *gx_bn = biginteger_to_bignum(env, gx);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+ BIGNUM *gy_bn = biginteger_to_bignum(env, gy);
+
+ EC_GROUP *result;
+ EC_POINT *g_point;
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ BIGNUM *p_bn = biginteger_to_bignum(env, p);
+ result = EC_GROUP_new_curve_GFp(p_bn, a_bn, b_bn, NULL);
+ BN_free(p_bn);
+ BN_free(a_bn);
+ BN_free(b_bn);
+
+ if (!result) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_new_curve_GFp.");
+ BN_free(gx_bn); BN_free(gy_bn);
+ return NULL;
+ }
+
+ g_point = EC_POINT_new(result);
+ if(!EC_POINT_set_affine_coordinates_GFp(result, g_point, gx_bn, gy_bn, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_POINT_set_affine_coordinates_GFp.");
+ BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ BIGNUM *n_bn = biginteger_to_bignum(env, n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = (*env)->CallIntMethod(env, params, get_h);
+ BIGNUM *h_bn = BN_new();
+ BN_set_word(h_bn, h);
+
+ if (!EC_GROUP_set_generator(result, g_point, n_bn, h_bn)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_set_generator.");
+ BN_free(n_bn); BN_free(h_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+
+ EC_POINT_free(g_point);
+ BN_free(gx_bn);
+ BN_free(gy_bn);
+ BN_free(n_bn);
+ BN_free(h_bn);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jboolean result = !curve;
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
+ BIGNUM *a;
+ BIGNUM *b;
+
+ BIGNUM *gx;
+ BIGNUM *gy;
+ jobject field;
+
+ BIGNUM *p = BN_new();
+ a = BN_new();
+ b = BN_new();
+ if (!EC_GROUP_get_curve_GFp(curve, p, a, b, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_curve_GFp.");
+ BN_free(p); BN_free(a); BN_free(b);
+ return NULL;
+ }
+
+ jobject p_int = bignum_to_biginteger(env, p);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int);
+
+ BN_free(p);
+
+ gx = BN_new();
+ gy = BN_new();
+ if (!EC_POINT_get_affine_coordinates_GFp(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_POINT_get_affine_coordinates_GFp.");
+ BN_free(a); BN_free(b); BN_free(gx); BN_free(gy);
+ return NULL;
+ }
+
+ jobject a_int = bignum_to_biginteger(env, a);
+ jobject b_int = bignum_to_biginteger(env, b);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int);
+
+ BN_free(a);
+ BN_free(b);
+
+ jobject gx_int = bignum_to_biginteger(env, gx);
+ jobject gy_int = bignum_to_biginteger(env, gy);
+
+ BN_free(gx);
+ BN_free(gy);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int);
+
+ jobject order = bignum_to_biginteger(env, EC_GROUP_get0_order(curve));
+ BIGNUM *h = BN_new();
+ EC_GROUP_get_cofactor(curve, h, NULL);
+ jint cofactor = BN_get_word(h);
+ BN_free(h);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order, cofactor);
+}
+
+static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
+ jint keysize = EC_GROUP_get_degree(curve);
+ unsigned long key_bytes = (keysize + 7) / 8;
+
+ EC_KEY *key = EC_KEY_new();
+ EC_KEY_set_group(key, curve);
+
+ native_timing_start();
+ int err = EC_KEY_generate_key(key);
+ native_timing_stop();
+
+ if (!err) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key.");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ BN_bn2bin_padded((unsigned char *) key_priv, key_bytes, EC_KEY_get0_private_key(key));
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ unsigned long key_len = 2*key_bytes + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, (unsigned char *) key_pub, key_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ EC_KEY_free(key);
+
+ jobject ec_param_spec = create_ec_param_spec(env, curve);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ break;
+ }
+ EC_GROUP_free(curve);
+ }
+
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize pub_len = (*env)->GetArrayLength(env, pub);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
+ EC_POINT *pub_point = EC_POINT_new(curve);
+ EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT);
+ EC_KEY_set_public_key(result, pub_point);
+ EC_POINT_free(pub_point);
+ return result;
+}
+
+EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize priv_len = (*env)->GetArrayLength(env, priv);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
+ BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT);
+ EC_KEY_set_private_key(result, s);
+ BN_free(s);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ int field_size = EC_GROUP_get_degree(curve);
+ size_t secret_len = (field_size + 7)/8;
+
+ //TODO: Do more KeyAgreements here, but will have to do the hash-fun manually,
+ // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string.
+ jbyteArray result = (*env)->NewByteArray(env, secret_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+
+ native_timing_start();
+ int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL);
+ native_timing_stop();
+
+ if (err <= 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key.");
+ EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ EC_KEY_free(pub);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually?
+
+ native_timing_start();
+ ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv);
+ native_timing_stop();
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ if (!signature) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign.");
+ EC_KEY_free(priv); EC_GROUP_free(curve);
+ return NULL;
+ }
+
+ jsize sig_len = i2d_ECDSA_SIG(signature, NULL);
+ jbyteArray result = (*env)->NewByteArray(env, sig_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ jbyte *result_data_ptr = result_data;
+ i2d_ECDSA_SIG(signature, (unsigned char **)&result_data_ptr);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ ECDSA_SIG_free(signature);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return JNI_FALSE;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+
+ jsize sig_len = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+ jbyte *sig_data_ptr = sig_data;
+ ECDSA_SIG *sig_obj = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig_data_ptr, sig_len);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub);
+ native_timing_stop();
+
+ if (result < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify.");
+ EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ ECDSA_SIG_free(sig_obj);
+ EC_KEY_free(pub);
+ EC_GROUP_free(curve);
+ return (result == 1) ? JNI_TRUE : JNI_FALSE;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/botan.cpp
new file mode 100644
index 0000000..c0d249c
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/botan.cpp
@@ -0,0 +1,528 @@
+#include "native.h"
+#include <string>
+
+#include <botan/version.h>
+#include <botan/rng.h>
+#include <botan/secmem.h>
+#include <botan/auto_rng.h>
+
+#include <botan/ec_group.h>
+#include <botan/ecc_key.h>
+#include <botan/ecdsa.h>
+#include <botan/eckcdsa.h>
+#include <botan/ecgdsa.h>
+#include <botan/ecdh.h>
+#include <botan/pubkey.h>
+#include "cpp_utils.hpp"
+#include "c_timing.h"
+
+static jclass provider_class;
+static Botan::AutoSeeded_RNG rng;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Botan");
+ provider_class = (jclass) env->NewGlobalRef(local_provider_class);
+
+ jmethodID init = env->GetMethodID(local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ const char* info_str = Botan::version_cstr();
+ const char* v_str = Botan::short_version_cstr();
+ std::string name_str = Botan::short_version_string();
+ name_str.insert(0, "Botan ");
+
+ jstring name = env->NewStringUTF(name_str.c_str());
+ double version = strtod(v_str, NULL);
+ jstring info = env->NewStringUTF(info_str);
+
+ return env->NewObject(provider_class, init, name, version, info);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup(JNIEnv *env, jobject self){
+ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ add_kpg(env, "ECDH", "BotanECDH", self, provider_put);
+ add_kpg(env, "ECDSA", "BotanECDSA", self, provider_put);
+ add_kpg(env, "ECKCDSA", "BotanECKCDSA", self, provider_put);
+ add_kpg(env, "ECGDSA", "BotanECGDSA", self, provider_put);
+
+ add_ka(env, "ECDH", "BotanECDH", self, provider_put);
+ add_ka(env, "ECDHwithSHA1KDF", "BotanECDHwithSHA1KDF", self, provider_put);
+ add_ka(env, "ECDHwithSHA224KDF", "BotanECDHwithSHA224KDF", self, provider_put);
+ add_ka(env, "ECDHwithSHA256KDF", "BotanECDHwithSHA256KDF", self, provider_put);
+ add_ka(env, "ECDHwithSHA384KDF", "BotanECDHwithSHA384KDF", self, provider_put);
+ add_ka(env, "ECDHwithSHA512KDF", "BotanECDHwithSHA512KDF", self, provider_put);
+
+ add_sig(env, "NONEwithECDSA", "BotanECDSAwithNONE", self, provider_put);
+ add_sig(env, "SHA1withECDSA", "BotanECDSAwithSHA1", self, provider_put);
+ add_sig(env, "SHA224withECDSA", "BotanECDSAwithSHA224", self, provider_put);
+ add_sig(env, "SHA256withECDSA", "BotanECDSAwithSHA256", self, provider_put);
+ add_sig(env, "SHA384withECDSA", "BotanECDSAwithSHA384", self, provider_put);
+ add_sig(env, "SHA512withECDSA", "BotanECDSAwithSHA512", self, provider_put);
+
+ add_sig(env, "NONEwithECKCDSA", "BotanECKCDSAwithNONE", self, provider_put);
+ add_sig(env, "SHA1withECKCDSA", "BotanECKCDSAwithSHA1", self, provider_put);
+ add_sig(env, "SHA224withECKCDSA", "BotanECKCDSAwithSHA224", self, provider_put);
+ add_sig(env, "SHA256withECKCDSA", "BotanECKCDSAwithSHA256", self, provider_put);
+ add_sig(env, "SHA384withECKCDSA", "BotanECKCDSAwithSHA384", self, provider_put);
+ add_sig(env, "SHA512withECKCDSA", "BotanECKCDSAwithSHA512", self, provider_put);
+
+ add_sig(env, "NONEwithECGDSA", "BotanECGDSAwithNONE", self, provider_put);
+ add_sig(env, "SHA1withECGDSA", "BotanECGDSAwithSHA1", self, provider_put);
+ add_sig(env, "SHA224withECGDSA", "BotanECGDSAwithSHA224", self, provider_put);
+ add_sig(env, "SHA256withECGDSA", "BotanECGDSAwithSHA256", self, provider_put);
+ add_sig(env, "SHA384withECGDSA", "BotanECGDSAwithSHA384", self, provider_put);
+ add_sig(env, "SHA512withECGDSA", "BotanECGDSAwithSHA512", self, provider_put);
+
+ init_classes(env, "Botan");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves(JNIEnv *env, jobject self){
+ jclass set_class = env->FindClass("java/util/TreeSet");
+
+ jmethodID set_ctr = env->GetMethodID(set_class, "<init>", "()V");
+ jmethodID set_add = env->GetMethodID(set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = env->NewObject(set_class, set_ctr);
+
+ const std::set<std::string>& curves = Botan::EC_Group::known_named_groups();
+ for (auto it = curves.begin(); it != curves.end(); ++it) {
+ std::string curve_name = *it;
+ jstring name_str = env->NewStringUTF(curve_name.c_str());
+ env->CallBooleanMethod(result, set_add, name_str);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported(JNIEnv *env, jobject self, jint keysize){
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(curve, get_field);
+
+ if (env->IsInstanceOf(field, fp_field_class)) {
+ return JNI_TRUE;
+ }
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ const std::set<std::string>& curves = Botan::EC_Group::known_named_groups();
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+ if (curves.find(str_name) != curves.end()) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+static jobject biginteger_from_bigint(JNIEnv *env, const Botan::BigInt& bigint) {
+ std::vector<uint8_t> bigint_data = Botan::BigInt::encode(bigint);
+ jbyteArray bigint_array = env->NewByteArray(bigint_data.size());
+ jbyte * bigint_bytes = env->GetByteArrayElements(bigint_array, NULL);
+ std::copy(bigint_data.begin(), bigint_data.end(), bigint_bytes);
+ env->ReleaseByteArrayElements(bigint_array, bigint_bytes, 0);
+
+ jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V");
+ return env->NewObject(biginteger_class, biginteger_init, (jint) 1, bigint_array);
+}
+
+static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) {
+ jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B");
+ jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(biginteger, to_byte_array);
+ jsize byte_length = env->GetArrayLength(byte_array);
+ jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL);
+ Botan::BigInt result((unsigned char *) byte_data, byte_length);
+ env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static Botan::EC_Group group_from_params(JNIEnv *env, jobject params) {
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(elliptic_curve, get_field);
+
+ jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = env->CallObjectMethod(elliptic_curve, get_a);
+
+ jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = env->CallObjectMethod(elliptic_curve, get_b);
+
+ jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = env->CallObjectMethod(field, get_p);
+
+ jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = env->CallObjectMethod(params, get_g);
+
+ jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = env->CallObjectMethod(g, get_x);
+
+ jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = env->CallObjectMethod(g, get_y);
+
+ jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = env->CallObjectMethod(params, get_n);
+
+ jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = env->CallIntMethod(params, get_h);
+
+ Botan::BigInt pi = bigint_from_biginteger(env, p);
+ Botan::BigInt ai = bigint_from_biginteger(env, a);
+ Botan::BigInt bi = bigint_from_biginteger(env, b);
+
+ Botan::BigInt gxi = bigint_from_biginteger(env, gx);
+ Botan::BigInt gyi = bigint_from_biginteger(env, gy);
+
+ Botan::BigInt ni = bigint_from_biginteger(env, n);
+ Botan::BigInt hi(h);
+
+ return Botan::EC_Group(pi, ai, bi, gxi, gyi, ni, hi);
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string curve_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+ return Botan::EC_Group(curve_name);
+ }
+ return Botan::EC_Group();
+}
+
+static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) {
+ jobject p = biginteger_from_bigint(env, group.get_p());
+
+ jmethodID fp_field_init = env->GetMethodID(fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject fp_field = env->NewObject(fp_field_class, fp_field_init, p);
+
+ jobject a = biginteger_from_bigint(env, group.get_a());
+ jobject b = biginteger_from_bigint(env, group.get_b());
+
+ jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, fp_field, a, b);
+
+ const Botan::PointGFp& generator = group.get_base_point();
+ jobject gx = biginteger_from_bigint(env, generator.get_affine_x());
+ jobject gy = biginteger_from_bigint(env, generator.get_affine_y());
+
+ jmethodID point_init = env->GetMethodID(point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = env->NewObject(point_class, point_init, gx, gy);
+
+ const Botan::BigInt& order = group.get_order();
+ jobject n = biginteger_from_bigint(env, order);
+
+ const Botan::BigInt& cofactor = group.get_cofactor();
+ jint h = (jint) cofactor.to_u32bit();
+
+ jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return env->NewObject(ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, h);
+}
+
+static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) {
+ jclass botan_kpg_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_kpg_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char* type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ std::unique_ptr<Botan::EC_PrivateKey> skey;
+ try {
+ native_timing_start();
+ if (type_str == "ECDH") {
+ skey = std::make_unique<Botan::ECDH_PrivateKey>(rng, group);
+ } else if (type_str == "ECDSA") {
+ skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, group);
+ } else if (type_str == "ECKCDSA") {
+ skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, group);
+ } else if (type_str == "ECGDSA") {
+ skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, group);
+ }
+ native_timing_stop();
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+
+ jobject ec_param_spec = params_from_group(env, group);
+
+ const Botan::PointGFp& pub_point = skey->public_point();
+ std::vector<uint8_t> pub_data = pub_point.encode(Botan::PointGFp::UNCOMPRESSED);
+
+ jbyteArray pub_bytearray = env->NewByteArray(pub_data.size());
+ jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL);
+ std::copy(pub_data.begin(), pub_data.end(), pub_bytes);
+ env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, 0);
+
+ jobject ec_pub_param_spec = env->NewLocalRef(ec_param_spec);
+ jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec);
+
+ const Botan::BigInt& priv_scalar = skey->private_value();
+ std::vector<uint8_t> priv_data = Botan::BigInt::encode(priv_scalar);
+
+ jbyteArray priv_bytearray = env->NewByteArray(priv_data.size());
+ jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL);
+ std::copy(priv_data.begin(), priv_data.end(), priv_bytes);
+ env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, 0);
+
+ jobject ec_priv_param_spec = env->NewLocalRef(ec_param_spec);
+ jmethodID ec_priv_init = env->GetMethodID(privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = env->NewObject(privkey_class, ec_priv_init, priv_bytearray, ec_priv_param_spec);
+
+ jmethodID keypair_init = env->GetMethodID(keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ return env->NewObject(keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){
+ const std::set<std::string>& curves = Botan::EC_Group::known_named_groups();
+ for (auto it = curves.begin(); it != curves.end(); ++it) {
+ Botan::EC_Group curve_group = Botan::EC_Group(*it);
+ size_t curve_size = curve_group.get_p_bits();
+ if (curve_size == (size_t) keysize) {
+ //generate on this group. Even thou no default groups are present...
+ return generate_from_group(env, self, curve_group);
+ }
+ }
+
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random){
+ Botan::EC_Group curve_group = group_from_params(env, params);
+ return generate_from_group(env, self, curve_group);
+}
+
+static std::string get_kdf(const std::string& type_str, size_t *kdf_bits) {
+ std::string kdf;
+ size_t key_len = 0;
+ if (type_str == "ECDH") {
+ kdf = "Raw";
+ //key len unused
+ } else if (type_str == "ECDHwithSHA1KDF") {
+ kdf = "KDF2(SHA-1)";
+ key_len = 20;
+ } else if (type_str == "ECDHwithSHA224KDF") {
+ kdf = "KDF2(SHA-224)";
+ key_len = 28;
+ } else if (type_str == "ECDHwithSHA256KDF") {
+ kdf = "KDF2(SHA-256)";
+ key_len = 32;
+ } else if (type_str == "ECDHwithSHA384KDF") {
+ kdf = "KDF2(SHA-384)";
+ key_len = 48;
+ } else if (type_str == "ECDHwithSHA512KDF") {
+ kdf = "KDF2(SHA-512)";
+ key_len = 64;
+ }
+
+ if (*kdf_bits == 0) {
+ *kdf_bits = key_len;
+ }
+
+ return kdf;
+}
+
+jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ Botan::EC_Group curve_group = group_from_params(env, params);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
+ Botan::BigInt privkey_scalar((unsigned char *) privkey_data, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
+
+ Botan::ECDH_PrivateKey skey(rng, curve_group, privkey_scalar);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ Botan::PointGFp public_point = curve_group.OS2ECP((uint8_t*) pubkey_data, pubkey_length);
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ Botan::ECDH_PublicKey pkey(curve_group, public_point);
+ //TODO: do check_key here?
+
+ jclass botan_ka_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_ka_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ size_t key_len = (get_kdf_bits(env, algorithm) + 7) / 8;
+ std::string kdf = get_kdf(type_str, &key_len);
+
+ Botan::PK_Key_Agreement ka(skey, rng, kdf);
+
+ std::vector<uint8_t> derived;
+ try {
+ native_timing_start();
+ derived = Botan::unlock(ka.derive_key(key_len, pkey.public_value()).bits_of());
+ native_timing_stop();
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+ jbyteArray result = env->NewByteArray(derived.size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(derived.begin(), derived.end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, 0);
+
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params){
+ return generate_secret(env, self, pubkey, privkey, params, NULL);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ jbyteArray secret = generate_secret(env, self, pubkey, privkey, params, algorithm);
+ if (secret == NULL) {
+ return NULL;
+ }
+ jmethodID spec_init = env->GetMethodID(secret_key_spec_class, "<init>", ("([BLjava/lang/String;)V"));
+ return env->NewObject(secret_key_spec_class, spec_init, secret, algorithm);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params){
+ Botan::EC_Group curve_group = group_from_params(env, params);
+
+ jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_bytes = env->GetByteArrayElements(privkey, NULL);
+ Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT);
+
+ std::unique_ptr<Botan::EC_PrivateKey> skey;
+ if (type_str.find("ECDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ } else if (type_str.find("ECKCDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ } else if (type_str.find("ECGDSA") != std::string::npos) {
+ skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, curve_group, privkey_scalar);
+ }
+
+ std::string emsa;
+ if (type_str.find("NONE") != std::string::npos) {
+ emsa = "Raw";
+ } else if (type_str.find("SHA1") != std::string::npos) {
+ emsa = "EMSA1(SHA-1)";
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ emsa = "EMSA1(SHA-224)";
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ emsa = "EMSA1(SHA-256)";
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ emsa = "EMSA1(SHA-384)";
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ emsa = "EMSA1(SHA-512)";
+ }
+
+ Botan::PK_Signer signer(*skey, rng, emsa, Botan::DER_SEQUENCE);
+
+ jsize data_length = env->GetArrayLength(data);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ std::vector<uint8_t> sig;
+ try {
+ native_timing_start();
+ sig = signer.sign_message((uint8_t*) data_bytes, data_length, rng);
+ native_timing_stop();
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ return NULL;
+ }
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+
+ jbyteArray result = env->NewByteArray(sig.size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(sig.begin(), sig.end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, 0);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params){
+ Botan::EC_Group curve_group = group_from_params(env, params);
+
+ jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan");
+ jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ Botan::PointGFp public_point = curve_group.OS2ECP((uint8_t*) pubkey_data, pubkey_length);
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ std::unique_ptr<Botan::EC_PublicKey> pkey;
+ if (type_str.find("ECDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECDSA_PublicKey>(curve_group, public_point);
+ } else if (type_str.find("ECKCDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECKCDSA_PublicKey>(curve_group, public_point);
+ } else if (type_str.find("ECGDSA") != std::string::npos) {
+ pkey = std::make_unique<Botan::ECGDSA_PublicKey>(curve_group, public_point);
+ }
+
+ std::string emsa;
+ if (type_str.find("NONE") != std::string::npos) {
+ emsa = "Raw";
+ } else if (type_str.find("SHA1") != std::string::npos) {
+ emsa = "EMSA1(SHA-1)";
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ emsa = "EMSA1(SHA-224)";
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ emsa = "EMSA1(SHA-256)";
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ emsa = "EMSA1(SHA-384)";
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ emsa = "EMSA1(SHA-512)";
+ }
+
+ Botan::PK_Verifier verifier(*pkey, emsa, Botan::DER_SEQUENCE);
+
+ jsize data_length = env->GetArrayLength(data);
+ jsize sig_length = env->GetArrayLength(signature);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ jbyte *sig_bytes = env->GetByteArrayElements(signature, NULL);
+
+ bool result;
+ try {
+ native_timing_start();
+ result = verifier.verify_message((uint8_t*)data_bytes, data_length, (uint8_t*)sig_bytes, sig_length);
+ native_timing_stop();
+ } catch (Botan::Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+ if (result) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.c
new file mode 100644
index 0000000..018ceda
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.c
@@ -0,0 +1,254 @@
+#include "c_timing.h"
+
+#if __linux || __posix
+
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+
+static unsigned long long tsc_start = 0;
+static unsigned long long tsc_end = 0;
+static unsigned long long tsc_partial = 0;
+static const char *rdtsc_unit = "instr";
+
+static inline unsigned long long rdtsc(void) {
+ unsigned long long int x;
+ __asm__ volatile ("rdtsc" : "=A" (x));
+ return x;
+}
+
+static jlong rdtsc_timing_resolution() {
+ return 1;
+}
+
+static void rdtsc_timing_start() {
+ tsc_partial = 0;
+ tsc_start = rdtsc();
+}
+
+static void rdtsc_timing_pause() {
+ tsc_end = rdtsc();
+ tsc_partial += tsc_end - tsc_start;
+}
+
+static void rdtsc_timing_restart() {
+ tsc_start = rdtsc();
+}
+
+static void rdtsc_timing_stop() {
+ tsc_end = rdtsc();
+}
+
+static jlong rdtsc_timing_last() {
+ jlong res = (jlong) ((tsc_end - tsc_start) + tsc_partial);
+ if (res < 0) {
+ return 0;
+ } else {
+ return res;
+ }
+}
+
+static struct timespec start = {0};
+static struct timespec end = {0};
+static jlong partial = 0;
+static clockid_t clk_id = CLOCK_MONOTONIC_RAW;
+static const char *clock_unit = "nano";
+
+static jlong clock_timing_resolution() {
+ struct timespec timeval;
+ clock_getres(clk_id, &timeval);
+ return timeval.tv_nsec;
+}
+
+static void clock_timing_start() {
+ partial = 0;
+ clock_gettime(clk_id, &start);
+}
+
+static void clock_timing_pause() {
+ clock_gettime(clk_id, &end);
+ partial += (end.tv_sec - start.tv_sec) * 1000000000 + (end.tv_nsec - start.tv_nsec);
+}
+
+static void clock_timing_restart() {
+ clock_gettime(clk_id, (struct timespec *)&start);
+}
+
+static void clock_timing_stop() {
+ clock_gettime(clk_id, (struct timespec *)&end);
+}
+
+static jlong clock_timing_last() {
+ jlong res = (end.tv_sec - start.tv_sec) * 1000000000 + (end.tv_nsec - start.tv_nsec) + partial;
+ if (res < 0) {
+ return 0;
+ } else {
+ return res;
+ }
+}
+
+static jlong (*func_timing_resolution)() = &clock_timing_resolution;
+static void (*func_timing_start)() = &clock_timing_start;
+static void (*func_timing_pause)() = &clock_timing_pause;
+static void (*func_timing_restart)() = &clock_timing_restart;
+static void (*func_timing_stop)() = &clock_timing_stop;
+static jlong (*func_timing_last)() = &clock_timing_last;
+static const char *unit = "nano";
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getNativeTimingSupport(JNIEnv *env, jobject self) {
+ jclass set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID set_ctr = (*env)->GetMethodID(env, set_class, "<init>", "()V");
+ jmethodID set_add = (*env)->GetMethodID(env, set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, set_class, set_ctr);
+ (*env)->CallBooleanMethod(env, result, set_add, (*env)->NewStringUTF(env, "rdtsc"));
+ (*env)->CallBooleanMethod(env, result, set_add, (*env)->NewStringUTF(env, "monotonic"));
+ (*env)->CallBooleanMethod(env, result, set_add, (*env)->NewStringUTF(env, "monotonic-raw"));
+ (*env)->CallBooleanMethod(env, result, set_add, (*env)->NewStringUTF(env, "cputime-processor"));
+ (*env)->CallBooleanMethod(env, result, set_add, (*env)->NewStringUTF(env, "cputime-thread"));
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_setNativeTimingType(JNIEnv *env, jobject self, jstring type) {
+ const char *type_data = (*env)->GetStringUTFChars(env, type, NULL);
+
+ if (strcmp(type_data, "rdtsc") == 0) {
+ func_timing_resolution = &rdtsc_timing_resolution;
+ func_timing_start = &rdtsc_timing_start;
+ func_timing_pause = &rdtsc_timing_pause;
+ func_timing_restart = &rdtsc_timing_restart;
+ func_timing_stop = &rdtsc_timing_stop;
+ func_timing_last = &rdtsc_timing_last;
+ unit = rdtsc_unit;
+ return JNI_TRUE;
+ } else {
+ if (strcmp(type_data, "monotonic") == 0) {
+ clk_id = CLOCK_MONOTONIC;
+ } else if (strcmp(type_data, "monotonic-raw") == 0) {
+ clk_id = CLOCK_MONOTONIC_RAW;
+ } else if (strcmp(type_data, "cputime-processor") == 0) {
+ clk_id = CLOCK_PROCESS_CPUTIME_ID;
+ } else if (strcmp(type_data, "cputime-thread") == 0) {
+ clk_id = CLOCK_THREAD_CPUTIME_ID;
+ } else {
+ return JNI_FALSE;
+ }
+
+ func_timing_resolution = &clock_timing_resolution;
+ func_timing_start = &clock_timing_start;
+ func_timing_pause = &clock_timing_pause;
+ func_timing_restart = &clock_timing_restart;
+ func_timing_stop = &clock_timing_stop;
+ func_timing_last = &clock_timing_last;
+ unit = clock_unit;
+ return JNI_TRUE;
+ }
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getNativeTimingResolution(JNIEnv *env, jobject self) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jstring JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getNativeTimingUnit(JNIEnv *env, jobject self) {
+ return (*env)->NewStringUTF(env, unit);
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getLastNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_last();
+}
+
+jlong native_timing_resolution() {
+ return func_timing_resolution();
+}
+
+void native_timing_start() {
+ func_timing_start();
+}
+
+void native_timing_pause() {
+ func_timing_pause();
+}
+
+void native_timing_restart() {
+ func_timing_restart();
+}
+
+void native_timing_stop() {
+ func_timing_stop();
+}
+
+jlong native_timing_last() {
+ return func_timing_last();
+}
+
+#elif defined(__WIN32__) || defined(_MSC_VER)
+
+#include <Windows.h>
+#error TODO
+
+static LARGE_INTEGER start = {0};
+static LARGE_INTEGER end = {0};
+static jlong partial = 0;
+
+jboolean native_timing_supported() {
+ return JNI_TRUE;
+}
+
+jlong native_timing_resolution() {
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ return 1000000000 / freq.QuadPart;
+}
+
+void native_timing_start() {
+ partial = 0;
+ QueryPerformanceCounter(&start);
+}
+
+void native_timing_pause() {
+ QueryPerformanceCounter(&end);
+ partial = (end.QuadPart - start.QuadPart) * native_timing_resolution();
+}
+
+void native_timing_restart() {
+ QueryPerformanceCounter(&start);
+}
+
+void native_timing_stop() {
+ QueryPerformanceCounter(&end);
+}
+
+jlong native_timing_last() {
+ jlong res = (end.QuadPart - start.QuadPart) * native_timing_resolution() + partial;
+ if (res < 0) {
+ return 0;
+ } else {
+ return res;
+ }
+}
+
+#else
+
+#error TODO
+jboolean native_timing_supported() {
+ return JNI_FALSE;
+}
+
+jlong native_timing_resolution() {
+ return 0;
+}
+
+void native_timing_start() {}
+
+void native_timing_pause() {}
+
+void native_timing_restart() {}
+
+void native_timing_stop() {}
+
+jlong native_timing_last() {
+ return 0;
+}
+
+#endif
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.h b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.h
new file mode 100644
index 0000000..e12ccdd
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_timing.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ *
+ */
+__attribute__((visibility("default"))) jlong native_timing_resolution();
+
+/**
+ *
+ */
+__attribute__((visibility("default"))) void native_timing_start();
+
+/**
+ *
+ */
+__attribute__((visibility("default"))) void native_timing_pause();
+
+/**
+ *
+ */
+__attribute__((visibility("default"))) void native_timing_restart();
+
+/**
+ *
+ */
+__attribute__((visibility("default"))) void native_timing_stop();
+
+/**
+ *
+ */
+__attribute__((visibility("default"))) jlong native_timing_last();
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.c
new file mode 100644
index 0000000..46286fd
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.c
@@ -0,0 +1,252 @@
+#include "c_utils.h"
+#define _ISOC99_SOURCE
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(__WIN32__) || defined(_MSC_VER)
+#include <windows.h>
+#endif
+
+jclass ec_parameter_spec_class;
+jclass ecgen_parameter_spec_class;
+jclass secret_key_spec_class;
+jclass pubkey_class;
+jclass privkey_class;
+jclass keypair_class;
+jclass elliptic_curve_class;
+jclass fp_field_class;
+jclass f2m_field_class;
+jclass point_class;
+jclass biginteger_class;
+jclass illegal_state_exception_class;
+
+void init_classes(JNIEnv *env, const char* lib_name) {
+ jclass local_ec_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECParameterSpec");
+ ec_parameter_spec_class = (*env)->NewGlobalRef(env, local_ec_parameter_spec_class);
+
+ jclass local_ecgen_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECGenParameterSpec");
+ ecgen_parameter_spec_class = (*env)->NewGlobalRef(env, local_ecgen_parameter_spec_class);
+
+ jclass local_secret_key_spec_class = (*env)->FindClass(env, "javax/crypto/spec/SecretKeySpec");
+ secret_key_spec_class = (*env)->NewGlobalRef(env, local_secret_key_spec_class);
+
+ const char *pubkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$";
+ char pubkey_class_name[2048] = { 0 }; //strlen(pubkey_base) + strlen(lib_name) + 1
+ pubkey_class_name[0] = 0;
+ strcat(pubkey_class_name, pubkey_base);
+ strcat(pubkey_class_name, lib_name);
+
+ jclass local_pubkey_class = (*env)->FindClass(env, pubkey_class_name);
+ pubkey_class = (*env)->NewGlobalRef(env, local_pubkey_class);
+
+ const char *privkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$";
+ char privkey_class_name[2048] = { 0 }; //strlen(privkey_base) + strlen(lib_name) + 1
+ privkey_class_name[0] = 0;
+ strcat(privkey_class_name, privkey_base);
+ strcat(privkey_class_name, lib_name);
+
+ jclass local_privkey_class = (*env)->FindClass(env, privkey_class_name);
+ privkey_class = (*env)->NewGlobalRef(env, local_privkey_class);
+
+ jclass local_keypair_class = (*env)->FindClass(env, "java/security/KeyPair");
+ keypair_class = (*env)->NewGlobalRef(env, local_keypair_class);
+
+ jclass local_elliptic_curve_class = (*env)->FindClass(env, "java/security/spec/EllipticCurve");
+ elliptic_curve_class = (*env)->NewGlobalRef(env, local_elliptic_curve_class);
+
+ jclass local_fp_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldFp");
+ fp_field_class = (*env)->NewGlobalRef(env, local_fp_field_class);
+
+ jclass local_f2m_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldF2m");
+ f2m_field_class = (*env)->NewGlobalRef(env, local_f2m_field_class);
+
+ jclass local_biginteger_class = (*env)->FindClass(env, "java/math/BigInteger");
+ biginteger_class = (*env)->NewGlobalRef(env, local_biginteger_class);
+
+ jclass local_point_class = (*env)->FindClass(env, "java/security/spec/ECPoint");
+ point_class = (*env)->NewGlobalRef(env, local_point_class);
+
+ jclass local_illegal_state_exception_class = (*env)->FindClass(env, "java/lang/IllegalStateException");
+ illegal_state_exception_class = (*env)->NewGlobalRef(env, local_illegal_state_exception_class);
+}
+
+void throw_new(JNIEnv *env, const char *class, const char *message) {
+ jclass clazz = (*env)->FindClass(env, class);
+ (*env)->ThrowNew(env, clazz, message);
+}
+
+void throw_new_var(JNIEnv *env, const char *class, const char *format, ...) {
+ char buffer[2048];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buffer, 2048, format, args);
+ va_end(args);
+ throw_new(env, class, buffer);
+}
+
+jint get_kdf_bits(JNIEnv *env, jstring algorithm) {
+ if (algorithm == NULL) {
+ return 0;
+ }
+
+ const char *algo_data = (*env)->GetStringUTFChars(env, algorithm, NULL);
+
+ jint result = 0;
+ if (strcmp(algo_data, "DES") == 0) {
+ result = 64;
+ } else if (strcmp(algo_data, "BLOWFISH") == 0) {
+ result = 128;
+ } else if (strcmp(algo_data, "DESEDE") == 0) {
+ result = 192;
+ } else if (strcmp(algo_data, "AES") == 0 || strcmp(algo_data, "CAMELLIA") == 0) {
+ result = 256;
+ } else {
+ char *end;
+ long bits = strtol(algo_data, &end, 10);
+ if (*end == 0) {
+ result = (jint) bits;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, algorithm, algo_data);
+ return result;
+}
+
+jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len) {
+ const jbyte *rtmp = r;
+ while (*rtmp++ == 0) {
+ r++;
+ r_len--;
+ }
+ const jbyte *stmp = s;
+ while (*stmp++ == 0) {
+ s++;
+ s_len--;
+ }
+
+ jbyte r_length = (jbyte) r_len + (r[0] & 0x80 ? 1 : 0);
+ jbyte s_length = (jbyte) s_len + (s[0] & 0x80 ? 1 : 0);
+
+ // R and S are < 128 bytes, so 1 byte tag + 1 byte len + len bytes value
+ size_t seq_value_len = 2 + r_length + 2 + s_length;
+ size_t whole_len = seq_value_len;
+
+ // The SEQUENCE length might be >= 128, so more bytes of length
+ size_t seq_len_len = 0;
+ if (seq_value_len >= 128) {
+ size_t s = seq_value_len;
+ do {
+ seq_len_len++;
+ } while ((s = s >> 8));
+ }
+ // seq_len_len bytes for length and one for length of length
+ whole_len += seq_len_len + 1;
+
+ // 1 byte tag for SEQUENCE
+ whole_len += 1;
+
+ jbyteArray result = (jbyteArray) (*env)->NewByteArray(env, whole_len);
+ jbyte *data = (*env)->GetByteArrayElements(env, result, NULL);
+ size_t i = 0;
+ data[i++] = 0x30; // SEQUENCE
+ if (seq_value_len < 128) {
+ data[i++] = (jbyte) seq_value_len;
+ } else {
+ data[i++] = (jbyte) (seq_len_len | (1 << 7));
+ for (size_t j = 0; j < seq_len_len; ++j) {
+ data[i++] = (jbyte) (seq_value_len & (0xff << (8 * (seq_len_len - j - 1))));
+ }
+ }
+ data[i++] = 0x02; //INTEGER
+ data[i++] = r_length;
+ if (r[0] & 0x80) {
+ data[i++] = 0;
+ }
+ memcpy(data + i, r, r_len);
+ i += r_len;
+ data[i++] = 0x02; //INTEGER
+ data[i++] = s_length;
+ if (s[0] & 0x80) {
+ data[i++] = 0;
+ }
+ memcpy(data + i, s, s_len);
+ i += s_len;
+ (*env)->ReleaseByteArrayElements(env, result, data, 0);
+
+ return result;
+}
+
+bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len) {
+ size_t sig_len = (*env)->GetArrayLength(env, sig);
+ jbyte *data = (*env)->GetByteArrayElements(env, sig, NULL);
+ size_t i = 0;
+ if (data[i++] != 0x30) {//SEQUENCE
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t seq_value_len = 0;
+ if (!(data[i] & 0x80)) {
+ seq_value_len = data[i++];
+ } else {
+ size_t seq_len_len = data[i++] & 0x7f;
+ while (seq_len_len > 0) {
+ seq_value_len |= (data[i++] << (seq_len_len - 1));
+ seq_len_len--;
+ }
+ }
+
+ if (data[i++] != 0x02) {//INTEGER
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t r_length = data[i++];
+ jbyte *r_out = malloc(r_length);
+ memcpy(r_out, data + i, r_length);
+ i += r_length;
+
+ if (data[i++] != 0x02) {//INTEGER
+ free(r_out);
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t s_length = data[i++];
+ jbyte *s_out = malloc(s_length);
+ memcpy(s_out, data + i, s_length);
+ i += s_length;
+
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ if (i != sig_len) {
+ free(r_out);
+ free(s_out);
+ return false;
+ }
+
+ *r_len = r_length;
+ *r_data = r_out;
+ *s_len = s_length;
+ *s_data = s_out;
+ return true;
+}
+
+char *biginteger_to_hex(JNIEnv *env, jobject big, jint bytes) {
+ jmethodID to_string = (*env)->GetMethodID(env, biginteger_class, "toString", "(I)Ljava/lang/String;");
+ jstring big_string = (*env)->CallObjectMethod(env, big, to_string, (jint) 16);
+
+ jsize len = (*env)->GetStringUTFLength(env, big_string);
+#if defined(__WIN32__) || defined(_MSC_VER)
+ char *raw_string = _alloca(len);
+#else
+ char raw_string[len];
+#endif
+ (*env)->GetStringUTFRegion(env, big_string, 0, len, raw_string);
+
+ char *result = calloc(bytes, 2);
+ if (len >= bytes) {
+ return strncpy(result, raw_string, 2*bytes);
+ } else {
+ jsize diff = bytes - len;
+ for (jint i = 0; i < diff*2; ++i) {
+ result[i] = '0';
+ }
+ return strncpy(result + diff*2, raw_string, 2*bytes);
+ }
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.h
new file mode 100644
index 0000000..f2f3f2f
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/c_utils.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "native.h"
+#include <stdbool.h>
+
+/**
+ * Classes that are accessed alot are cached here, manually.
+ */
+extern jclass ec_parameter_spec_class;
+extern jclass ecgen_parameter_spec_class;
+extern jclass secret_key_spec_class;
+extern jclass pubkey_class;
+extern jclass privkey_class;
+extern jclass keypair_class;
+extern jclass elliptic_curve_class;
+extern jclass fp_field_class;
+extern jclass f2m_field_class;
+extern jclass point_class;
+extern jclass biginteger_class;
+extern jclass illegal_state_exception_class;
+
+/**
+ * Initialize the classes.
+ */
+void init_classes(JNIEnv *env, const char* lib_name);
+
+/**
+ * Throw a new exception of class with message.
+ */
+void throw_new(JNIEnv *env, const char *class, const char *message);
+
+/**
+ * Throw a new exception of class, with formatted message.
+ */
+void throw_new_var(JNIEnv *env, const char *class, const char *format, ...);
+
+/**
+ * Get the size of the specified key algorithm in bits, for ECDH KDF output size.
+ */
+jint get_kdf_bits(JNIEnv *env, jstring algorithm);
+
+/**
+ * DER encode the r and s values.
+ */
+jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len);
+
+/**
+ * DER decode a signature into r and s values.
+ */
+bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len);
+
+/**
+ * Convert a BigInteger to an allocated hex string.
+ */
+char *biginteger_to_hex(JNIEnv *env, jobject big, jint bytes);
+
+/**
+ * Some useful defines to init the provider.
+ */
+#define INIT_PROVIDER(env, provider_class) jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")
+#define ADD_PROPERTY(env, self, base_name, base_class, prop_name, prop_class) do { \
+ jstring ec = (*env)->NewStringUTF(env, base_name prop_name); \
+ jstring ec_value = (*env)->NewStringUTF(env, base_class prop_class); \
+ (*env)->CallObjectMethod(env, self, provider_put, ec, ec_value); \
+ } while (0)
+#define ADD_KPG(env, self, kpg_name, kpg_class) ADD_PROPERTY(env, self, "KeyPairGenerator.", "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$", kpg_name, kpg_class)
+#define ADD_KA(env, self, ka_name, ka_class) ADD_PROPERTY(env, self, "KeyAgreement.", "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$", ka_name, ka_class)
+#define ADD_SIG(env, self, sig_name, sig_class) ADD_PROPERTY(env, self, "Signature.", "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$", sig_name, sig_class) \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp
new file mode 100644
index 0000000..20d9a3c
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp
@@ -0,0 +1,115 @@
+#include "cpp_utils.hpp"
+
+jclass ec_parameter_spec_class;
+jclass ecgen_parameter_spec_class;
+jclass secret_key_spec_class;
+jclass pubkey_class;
+jclass privkey_class;
+jclass keypair_class;
+jclass elliptic_curve_class;
+jclass fp_field_class;
+jclass f2m_field_class;
+jclass point_class;
+jclass biginteger_class;
+jclass illegal_state_exception_class;
+
+void init_classes(JNIEnv *env, std::string lib_name) {
+ jclass local_ec_parameter_spec_class = env->FindClass("java/security/spec/ECParameterSpec");
+ ec_parameter_spec_class = (jclass) env->NewGlobalRef(local_ec_parameter_spec_class);
+
+ jclass local_ecgen_parameter_spec_class = env->FindClass("java/security/spec/ECGenParameterSpec");
+ ecgen_parameter_spec_class = (jclass) env->NewGlobalRef(local_ecgen_parameter_spec_class);
+
+ jclass local_secret_key_spec_class = env->FindClass("javax/crypto/spec/SecretKeySpec");
+ secret_key_spec_class = (jclass) env->NewGlobalRef(local_secret_key_spec_class);
+
+ std::string pubkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$");
+ pubkey_class_name += lib_name;
+
+ jclass local_pubkey_class = env->FindClass(pubkey_class_name.c_str());
+ pubkey_class = (jclass) env->NewGlobalRef(local_pubkey_class);
+
+ std::string privkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$");
+ privkey_class_name += lib_name;
+
+ jclass local_privkey_class = env->FindClass(privkey_class_name.c_str());
+ privkey_class = (jclass) env->NewGlobalRef(local_privkey_class);
+
+ jclass local_keypair_class = env->FindClass("java/security/KeyPair");
+ keypair_class = (jclass) env->NewGlobalRef(local_keypair_class);
+
+ jclass local_elliptic_curve_class = env->FindClass("java/security/spec/EllipticCurve");
+ elliptic_curve_class = (jclass) env->NewGlobalRef(local_elliptic_curve_class);
+
+ jclass local_fp_field_class = env->FindClass("java/security/spec/ECFieldFp");
+ fp_field_class = (jclass) env->NewGlobalRef(local_fp_field_class);
+
+ jclass local_f2m_field_class = env->FindClass("java/security/spec/ECFieldF2m");
+ f2m_field_class = (jclass) env->NewGlobalRef(local_f2m_field_class);
+
+ jclass local_biginteger_class = env->FindClass("java/math/BigInteger");
+ biginteger_class = (jclass) env->NewGlobalRef(local_biginteger_class);
+
+ jclass local_point_class = env->FindClass("java/security/spec/ECPoint");
+ point_class = (jclass) env->NewGlobalRef(local_point_class);
+
+ jclass local_illegal_state_exception_class = env->FindClass("java/lang/IllegalStateException");
+ illegal_state_exception_class = (jclass) env->NewGlobalRef(local_illegal_state_exception_class);
+}
+
+void throw_new(JNIEnv *env, const std::string& klass, const std::string& message) {
+ jclass clazz = env->FindClass(klass.c_str());
+ env->ThrowNew(clazz, message.c_str());
+}
+
+jint get_kdf_bits(JNIEnv *env, jstring algorithm) {
+ if (algorithm == NULL) {
+ return 0;
+ }
+
+ const char *algo_data = env->GetStringUTFChars(algorithm, NULL);
+ std::string algo(algo_data);
+
+ jint result = 0;
+ if (algo == "DES") {
+ result = 64;
+ } else if (algo == "BLOWFISH") {
+ result = 128;
+ } else if (algo == "DESEDE") {
+ result = 192;
+ } else if (algo == "AES" || algo == "CAMELLIA") {
+ result = 256;
+ } else {
+ char *end;
+ long bits = strtol(algo_data, &end, 10);
+ if (*end == 0) {
+ result = (jint) bits;
+ }
+ }
+ env->ReleaseStringUTFChars(algorithm, algo_data);
+ return result;
+}
+
+static void add_provider_property(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) {
+ jstring type_str = env->NewStringUTF(type.c_str());
+ jstring class_str = env->NewStringUTF(klass.c_str());
+ env->CallObjectMethod(provider, put_method, type_str, class_str);
+}
+
+void add_kpg(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) {
+ const std::string full_type = "KeyPairGenerator." + type;
+ const std::string full_class = "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$" + klass;
+ add_provider_property(env, full_type, full_class, provider, put_method);
+}
+
+void add_ka(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) {
+ const std::string full_type = "KeyAgreement." + type;
+ const std::string full_class = "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$" + klass;
+ add_provider_property(env, full_type, full_class, provider, put_method);
+}
+
+void add_sig(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method) {
+ const std::string full_type = "Signature." + type;
+ const std::string full_class = "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$" + klass;
+ add_provider_property(env, full_type, full_class, provider, put_method);
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp
new file mode 100644
index 0000000..ed26c01
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "native.h"
+#include <string>
+
+/**
+ * Classes that are accessed alot are cached here, manually.
+ */
+extern jclass ec_parameter_spec_class;
+extern jclass ecgen_parameter_spec_class;
+extern jclass secret_key_spec_class;
+extern jclass pubkey_class;
+extern jclass privkey_class;
+extern jclass keypair_class;
+extern jclass elliptic_curve_class;
+extern jclass fp_field_class;
+extern jclass f2m_field_class;
+extern jclass point_class;
+extern jclass biginteger_class;
+extern jclass illegal_state_exception_class;
+
+/**
+ * Initialize the classes.
+ */
+void init_classes(JNIEnv *env, std::string lib_name);
+
+/**
+ * Throw a new exception of class with message.
+ */
+void throw_new(JNIEnv *env, const std::string& klass, const std::string& message);
+
+/**
+ * Get the size of the specified key algorithm in bits, for ECDH KDF output size.
+ */
+jint get_kdf_bits(JNIEnv *env, jstring algorithm);
+
+/**
+ * Add a KeyPairGeneratorSpi class to this provider.
+ */
+void add_kpg(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method);
+
+/**
+ * Add a KeyAgreementSpi class to this provider.
+ */
+void add_ka(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method);
+
+/**
+ * Add a SignatureSpi class to this provider.
+ */
+void add_sig(JNIEnv *env, const std::string &type, const std::string &klass, jobject provider, jmethodID put_method); \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
new file mode 100644
index 0000000..eb782b7
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
@@ -0,0 +1,767 @@
+#include "native.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+#include <string>
+#include <sstream>
+using std::string;
+
+#include <stdexcept>
+using std::runtime_error;
+
+#include <cstdlib>
+using std::exit;
+
+#include "cryptopp/cryptlib.h"
+using CryptoPP::Exception;
+
+#include "cryptopp/config.h"
+using CryptoPP::byte;
+
+#include "cryptopp/osrng.h"
+using CryptoPP::AutoSeededRandomPool;
+
+#include "cryptopp/sha.h"
+using CryptoPP::SHA1;
+using CryptoPP::SHA224;
+using CryptoPP::SHA256;
+using CryptoPP::SHA384;
+using CryptoPP::SHA512;
+
+#include "cryptopp/aes.h"
+using CryptoPP::AES;
+
+#include "cryptopp/modarith.h"
+using CryptoPP::ModularArithmetic;
+
+#include "cryptopp/gf2n.h"
+using CryptoPP::PolynomialMod2;
+using CryptoPP::GF2NP;
+using CryptoPP::GF2NT;
+using CryptoPP::GF2NPP;
+
+#include "cryptopp/eccrypto.h"
+using CryptoPP::ECP;
+using CryptoPP::EC2N;
+using CryptoPP::ECDH;
+using CryptoPP::DL_GroupParameters_EC;
+using CryptoPP::ECDSA;
+
+#include "cryptopp/secblock.h"
+using CryptoPP::SecByteBlock;
+
+#include "cryptopp/oids.h"
+using CryptoPP::OID;
+
+#include "cryptopp/dsa.h"
+using CryptoPP::DSAConvertSignatureFormat;
+using CryptoPP::DSA_DER;
+using CryptoPP::DSA_P1363;
+
+// ASN1 is a namespace, not an object
+#include "cryptopp/asn.h"
+using namespace CryptoPP::ASN1;
+
+#include "cryptopp/integer.h"
+using CryptoPP::Integer;
+
+
+#include "cpp_utils.hpp"
+#include "c_timing.h"
+
+static jclass provider_class;
+static AutoSeededRandomPool rng;
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Cryptopp");
+ provider_class = (jclass) env->NewGlobalRef(local_provider_class);
+
+ jmethodID init = env->GetMethodID(local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ std::string lib_name = "Crypto++";
+
+ int lib_version = CRYPTOPP_VERSION;
+ std::string info_str = std::to_string(lib_version);
+ std::stringstream ss;
+ ss << lib_name << " ";
+ ss << info_str[0];
+ for (size_t i = 1; i < info_str.size(); ++i) {
+ ss << "." << info_str[i];
+ }
+
+ jstring name = env->NewStringUTF(lib_name.c_str());
+ double version = lib_version / 100;
+ jstring info = env->NewStringUTF(ss.str().c_str());
+
+ return env->NewObject(provider_class, init, name, version, info);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Cryptopp_setup(JNIEnv *env, jobject self){
+ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ add_kpg(env, "ECDH", "CryptoppECDH", self, provider_put);
+ add_kpg(env, "ECDSA", "CryptoppECDSA", self, provider_put);
+
+ add_ka(env, "ECDH", "CryptoppECDH", self, provider_put);
+
+ add_sig(env, "SHA1withECDSA", "CryptoppECDSAwithSHA1", self, provider_put);
+ add_sig(env, "SHA224withECDSA", "CryptoppECDSAwithSHA224", self, provider_put);
+ add_sig(env, "SHA256withECDSA", "CryptoppECDSAwithSHA256", self, provider_put);
+ add_sig(env, "SHA384withECDSA", "CryptoppECDSAwithSHA384", self, provider_put);
+ add_sig(env, "SHA512withECDSA", "CryptoppECDSAwithSHA512", self, provider_put);
+
+ init_classes(env, "Cryptopp");
+}
+
+template <class EC> static std::vector<OID> get_curve_oids() {
+ std::vector<OID> oids;
+ OID it = OID();
+ do {
+ it = DL_GroupParameters_EC<EC>::GetNextRecommendedParametersOID(it);
+ if (it == OID()) {
+ break;
+ }
+ oids.push_back(it);
+ } while (true);
+
+ return oids;
+}
+
+static std::vector<OID> get_all_curve_oids() {
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ std::vector<OID> ec2n_oids = get_curve_oids<EC2N>();
+
+ std::vector<OID> all_oids;
+ all_oids.insert(all_oids.end(), ecp_oids.begin(), ecp_oids.end());
+ all_oids.insert(all_oids.end(), ec2n_oids.begin(), ec2n_oids.end());
+ return all_oids;
+}
+
+static std::string oid_to_str(const OID &oid) {
+ const std::vector<CryptoPP::word32>& oid_values = oid.GetValues();
+ std::stringstream ss;
+ for (size_t i = 0; i < oid_values.size(); ++i) {
+ if(i != 0)
+ ss << ".";
+ ss << std::to_string(oid_values[i]);
+ }
+ return ss.str();
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getCurves(JNIEnv *env, jobject self){
+ jclass set_class = env->FindClass("java/util/TreeSet");
+
+ jmethodID set_ctr = env->GetMethodID(set_class, "<init>", "()V");
+ jmethodID set_add = env->GetMethodID(set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = env->NewObject(set_class, set_ctr);
+
+ std::vector<OID> all_oids = get_all_curve_oids();
+
+ for (auto oid = all_oids.begin(); oid != all_oids.end(); ++oid) {
+ jstring name_str = env->NewStringUTF(oid_to_str(*oid).c_str());
+ env->CallBooleanMethod(result, set_add, name_str);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_keysizeSupported(JNIEnv *env, jobject self, jint keysize){
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) {
+ DL_GroupParameters_EC<ECP> group(*oid);
+ if (((jint) group.GetCurve().GetField().MaxElementBitLength()) == keysize) {
+ return JNI_TRUE;
+ }
+ }
+
+ std::vector<OID> e2n_oids = get_curve_oids<EC2N>();
+ for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) {
+ DL_GroupParameters_EC<EC2N> group(*oid);
+ if (((jint) group.GetCurve().FieldSize().ConvertToLong()) == keysize) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ // Any custom params should be supported.
+ return JNI_TRUE;
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ // Compare with OIDs I guess?
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+
+ std::vector<OID> all_oids = get_all_curve_oids();
+ for (auto oid = all_oids.begin(); oid != all_oids.end(); ++oid) {
+ std::string oid_s = oid_to_str(*oid);
+ if (str_name == oid_s) {
+ return JNI_TRUE;
+ }
+ }
+ }
+ return JNI_FALSE;
+}
+
+static Integer integer_from_biginteger(JNIEnv *env, jobject bigint) {
+ jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(bigint, to_byte_array);
+ jsize byte_length = env->GetArrayLength(byte_array);
+ jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL);
+ Integer result((byte *) byte_data, (size_t) byte_length);
+ env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static jobject biginteger_from_integer(JNIEnv *env, const Integer &integer) {
+ jbyteArray byte_array = (jbyteArray) env->NewByteArray(integer.MinEncodedSize());
+
+ jbyte *bigint_bytes = env->GetByteArrayElements(byte_array, NULL);
+ integer.Encode((byte *) bigint_bytes, integer.MinEncodedSize());
+ env->ReleaseByteArrayElements(byte_array, bigint_bytes, 0);
+
+ jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V");
+ return env->NewObject(biginteger_class, biginteger_init, (jint) 1, byte_array);
+}
+
+static jobject biginteger_from_polmod2(JNIEnv *env, const PolynomialMod2 &polmod) {
+ jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V");
+
+ jbyteArray mod_array = env->NewByteArray(polmod.MinEncodedSize());
+ jbyte *mod_data = env->GetByteArrayElements(mod_array, NULL);
+ polmod.Encode((byte *) mod_data, polmod.MinEncodedSize());
+ env->ReleaseByteArrayElements(mod_array, mod_data, 0);
+
+ return env->NewObject(biginteger_class, biginteger_init, (jint) 1, mod_array);
+}
+
+static std::unique_ptr<DL_GroupParameters_EC<ECP>> fp_group_from_params(JNIEnv *env, jobject params) {
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(elliptic_curve, get_field);
+
+ if (!env->IsInstanceOf(field, fp_field_class)) {
+ return nullptr;
+ }
+
+ jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = env->CallObjectMethod(elliptic_curve, get_a);
+ Integer ai = integer_from_biginteger(env, a);
+
+ jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = env->CallObjectMethod(elliptic_curve, get_b);
+ Integer bi = integer_from_biginteger(env, b);
+
+ jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = env->CallObjectMethod(params, get_g);
+
+ jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = env->CallObjectMethod(g, get_x);
+
+ jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = env->CallObjectMethod(g, get_y);
+
+ jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = env->CallObjectMethod(params, get_n);
+ Integer ni = integer_from_biginteger(env, n);
+
+ jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = env->CallIntMethod(params, get_h);
+ Integer hi(h);
+
+ jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = env->CallObjectMethod(field, get_p);
+ Integer pi = integer_from_biginteger(env, p);
+
+ ECP curve(pi, ai, bi);
+
+ Integer gxi = integer_from_biginteger(env, gx);
+ Integer gyi = integer_from_biginteger(env, gy);
+ ECP::Point g_point(gxi, gyi);
+
+ return std::make_unique<DL_GroupParameters_EC<ECP>>(curve, g_point, ni, hi);
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) {
+ std::string oid_s = oid_to_str(*oid);
+ if (str_name == oid_s) {
+ return std::make_unique<DL_GroupParameters_EC<ECP>>(*oid);
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+static std::unique_ptr<DL_GroupParameters_EC<EC2N>> f2m_group_from_params(JNIEnv *env, jobject params) {
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(elliptic_curve, get_field);
+
+ if (!env->IsInstanceOf(field, f2m_field_class)) {
+ return nullptr;
+ }
+
+ jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = env->CallObjectMethod(elliptic_curve, get_a);
+ Integer ai = integer_from_biginteger(env, a);
+
+ jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = env->CallObjectMethod(elliptic_curve, get_b);
+ Integer bi = integer_from_biginteger(env, b);
+
+ jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = env->CallObjectMethod(params, get_g);
+
+ jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = env->CallObjectMethod(g, get_x);
+
+ jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = env->CallObjectMethod(g, get_y);
+
+ jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = env->CallObjectMethod(params, get_n);
+ Integer ni = integer_from_biginteger(env, n);
+
+ jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = env->CallIntMethod(params, get_h);
+ Integer hi(h);
+
+ jmethodID get_midterms = env->GetMethodID(f2m_field_class, "getMidTermsOfReductionPolynomial", "()[I");
+ jintArray midterms = (jintArray) env->CallObjectMethod(field, get_midterms);
+ jsize midterm_length = env->GetArrayLength(midterms);
+ jint *midterm_data = env->GetIntArrayElements(midterms, NULL);
+
+ jmethodID get_m = env->GetMethodID(f2m_field_class, "getM", "()I");
+ jint m = env->CallIntMethod(field, get_m);
+
+ std::unique_ptr<GF2NP> base_field;
+ if (midterm_length == 1) {
+ //trinomial, use GF2NT
+ base_field = std::make_unique<GF2NT>((unsigned int) m, (unsigned int) midterm_data[0], 0);
+ } else {
+ //pentanomial, use GF2NPP
+ base_field = std::make_unique<GF2NPP>((unsigned int) m, (unsigned int) midterm_data[0], (unsigned int) midterm_data[1], (unsigned int) midterm_data[2], 0);
+ }
+ env->ReleaseIntArrayElements(midterms, midterm_data, JNI_ABORT);
+
+ jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B");
+ jbyteArray a_array = (jbyteArray) env->CallObjectMethod(a, to_byte_array);
+ jsize a_length = env->GetArrayLength(a_array);
+ jbyte *a_data = env->GetByteArrayElements(a_array, NULL);
+
+ jbyteArray b_array = (jbyteArray) env->CallObjectMethod(b, to_byte_array);
+ jsize b_length = env->GetArrayLength(b_array);
+ jbyte *b_data = env->GetByteArrayElements(b_array, NULL);
+
+ EC2N curve(*base_field, EC2N::FieldElement((byte *) a_data, (size_t) a_length), EC2N::FieldElement((byte *) b_data, (size_t) b_length));
+ env->ReleaseByteArrayElements(a_array, a_data, JNI_ABORT);
+ env->ReleaseByteArrayElements(b_array, b_data, JNI_ABORT);
+
+ jbyteArray gx_array = (jbyteArray) env->CallObjectMethod(gx, to_byte_array);
+ jsize gx_length = env->GetArrayLength(gx_array);
+ jbyte *gx_data = env->GetByteArrayElements(gx_array, NULL);
+ PolynomialMod2 gxm((byte *) gx_data, (size_t) gx_length);
+ env->ReleaseByteArrayElements(gx_array, gx_data, JNI_ABORT);
+
+ jbyteArray gy_array = (jbyteArray) env->CallObjectMethod(gy, to_byte_array);
+ jsize gy_length = env->GetArrayLength(gy_array);
+ jbyte *gy_data = env->GetByteArrayElements(gy_array, NULL);
+ PolynomialMod2 gym((byte *) gy_data, (size_t) gy_length);
+ env->ReleaseByteArrayElements(gy_array, gy_data, JNI_ABORT);
+
+ EC2N::Point g_point(gxm, gym);
+
+ return std::make_unique<DL_GroupParameters_EC<EC2N>>(curve, g_point, ni, hi);
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+
+ std::vector<OID> e2n_oids = get_curve_oids<EC2N>();
+ for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) {
+ std::string oid_s = oid_to_str(*oid);
+ if (str_name == oid_s) {
+ return std::make_unique<DL_GroupParameters_EC<EC2N>>(*oid);
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+template <class EC> jobject finish_params(JNIEnv *env, jobject field, jobject a, jobject b, jobject gx, jobject gy, DL_GroupParameters_EC<EC> group) {
+ jmethodID point_init = env->GetMethodID(point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = env->NewObject(point_class, point_init, gx, gy);
+
+ jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, field, a, b);
+
+ // Integer GetSubgroupOrder
+ // Integer GetCofactor
+ jobject order = biginteger_from_integer(env, group.GetSubgroupOrder());
+ jint cofactor = (jint) group.GetCofactor().ConvertToLong();
+
+ jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return env->NewObject(ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order, cofactor);
+}
+
+template <class EC> jobject params_from_group(JNIEnv *env, DL_GroupParameters_EC<EC> group) {
+ return NULL;
+}
+
+template <> jobject params_from_group<ECP>(JNIEnv *env, DL_GroupParameters_EC<ECP> group) {
+ ECP curve = group.GetCurve();
+ jmethodID fp_field_init = env->GetMethodID(fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ ModularArithmetic mod = curve.GetField();
+ jobject p = biginteger_from_integer(env, mod.GetModulus());
+ jobject a = biginteger_from_integer(env, curve.GetA());
+ jobject b = biginteger_from_integer(env, curve.GetB());
+
+ jobject field = env->NewObject(fp_field_class, fp_field_init, p);
+
+ ECP::Point gp = group.GetBasePrecomputation().GetBase(group.GetGroupPrecomputation());
+ jobject gx = biginteger_from_integer(env, gp.x);
+ jobject gy = biginteger_from_integer(env, gp.y);
+ return finish_params(env, field, a, b, gx, gy, group);
+}
+
+template <> jobject params_from_group<EC2N>(JNIEnv *env, DL_GroupParameters_EC<EC2N> group) {
+ EC2N curve = group.GetCurve();
+ PolynomialMod2 mod = curve.GetField().GetModulus();
+ int m = mod.Degree();
+ unsigned int coeff_count = mod.CoefficientCount();
+ jintArray ks;
+ int to_find;
+ int found = 0;
+ if (coeff_count == 3) {
+ //trinomial
+ ks = env->NewIntArray(1);
+ to_find = 1;
+ } else if (coeff_count == 5) {
+ //pentanomial
+ ks = env->NewIntArray(3);
+ to_find = 3;
+ } else {
+ return NULL;
+ }
+ jint *ks_data = env->GetIntArrayElements(ks, NULL);
+ for (int i = m - 1; i > 0 && found < to_find; --i) {
+ if (mod.GetCoefficient(i) == 1) {
+ ks_data[found++] = i;
+ }
+ }
+ env->ReleaseIntArrayElements(ks, ks_data, 0);
+
+ jmethodID f2m_field_init = env->GetMethodID(f2m_field_class, "<init>", "(I[I)V");
+ jobject field = env->NewObject(f2m_field_class, f2m_field_init, (jint) m, ks);
+
+ jobject a = biginteger_from_polmod2(env, curve.GetA());
+ jobject b = biginteger_from_polmod2(env, curve.GetB());
+
+ EC2N::Point gp = group.GetBasePrecomputation().GetBase(group.GetGroupPrecomputation());
+ jobject gx = biginteger_from_polmod2(env, gp.x);
+ jobject gy = biginteger_from_polmod2(env, gp.y);
+ return finish_params(env, field, a, b, gx, gy, group);
+}
+
+template <class EC> jobject generate_from_group(JNIEnv *env, DL_GroupParameters_EC<EC> group, jobject params) {
+ typename ECDH<EC>::Domain ec_domain(group);
+ SecByteBlock priv(ec_domain.PrivateKeyLength()), pub(ec_domain.PublicKeyLength());
+
+ try {
+ native_timing_start();
+ ec_domain.GenerateKeyPair(rng, priv, pub);
+ native_timing_stop();
+ } catch (Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+
+ jbyteArray pub_bytearray = env->NewByteArray(pub.SizeInBytes());
+ jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL);
+ std::copy(pub.BytePtr(), pub.BytePtr()+pub.SizeInBytes(), pub_bytes);
+ env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, 0);
+
+ jobject ec_pub_param_spec = env->NewLocalRef(params);
+ jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec);
+
+ jbyteArray priv_bytearray = env->NewByteArray(priv.SizeInBytes());
+ jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL);
+ std::copy(priv.BytePtr(), priv.BytePtr()+priv.SizeInBytes(), priv_bytes);
+ env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, 0);
+
+ jobject ec_priv_param_spec = env->NewLocalRef(params);
+ jmethodID ec_priv_init = env->GetMethodID(privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = env->NewObject(privkey_class, ec_priv_init, priv_bytearray, ec_priv_param_spec);
+
+ jmethodID keypair_init = env->GetMethodID(keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ return env->NewObject(keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) {
+ DL_GroupParameters_EC<ECP> group(*oid);
+ if (((jint) group.GetCurve().GetField().MaxElementBitLength()) == keysize) {
+ jobject params = params_from_group(env, group);
+ return generate_from_group<ECP>(env, group, params);
+ }
+ }
+
+ std::vector<OID> e2n_oids = get_curve_oids<EC2N>();
+ for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) {
+ DL_GroupParameters_EC<EC2N> group(*oid);
+ if ((jint) group.GetCurve().FieldSize().ConvertToLong() == keysize) {
+ jobject params = params_from_group(env, group);
+ return generate_from_group<EC2N>(env, group, params);
+ }
+ }
+ return NULL;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) {
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+ return generate_from_group<EC2N>(env, *ec2n_group, params);
+ } else {
+ return generate_from_group<ECP>(env, *ecp_group, params);
+ }
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
+ SecByteBlock private_key((byte *) privkey_data, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ SecByteBlock public_key((byte *) pubkey_data, pubkey_length);
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ bool success;
+ std::unique_ptr<SecByteBlock> secret;
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+ ECDH<EC2N>::Domain dh_agreement(*ec2n_group);
+
+ try {
+ secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength());
+ native_timing_start();
+ success = dh_agreement.Agree(*secret, private_key, public_key);
+ native_timing_stop();
+ } catch (Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+ } else {
+ ECDH<ECP>::Domain dh_agreement(*ecp_group);
+
+ try {
+ secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength());
+ native_timing_start();
+ success = dh_agreement.Agree(*secret, private_key, public_key);
+ native_timing_stop();
+ } catch (Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+ }
+ if (!success) {
+ throw_new(env, "java/security/GeneralSecurityException", "Agreement was unsuccessful.");
+ return NULL;
+ }
+
+ jbyteArray result = env->NewByteArray(secret->size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(secret->begin(), secret->end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, 0);
+
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm){
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+template <class EC, class H>
+jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray data, const Integer & private_key_x) {
+
+ typename ECDSA<EC, H>::PrivateKey pkey;
+ pkey.Initialize(group, private_key_x);
+ typename ECDSA<EC, H>::Signer signer(pkey);
+
+ std::string signature(signer.MaxSignatureLength(), 0);
+
+ jsize data_length = env->GetArrayLength(data);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ native_timing_start();
+ size_t len = signer.SignMessage(rng, (byte *)data_bytes, data_length, (byte *)signature.c_str());
+ native_timing_stop();
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ signature.resize(len);
+
+ byte sig[4096];
+ size_t sig_len = DSAConvertSignatureFormat(sig, sizeof(sig), DSA_DER, (byte *)signature.c_str(), len, DSA_P1363);
+
+ jbyteArray result = env->NewByteArray(sig_len);
+ jbyte *result_bytes = env->GetByteArrayElements(result, NULL);
+ std::copy(sig, sig+sig_len, result_bytes);
+ env->ReleaseByteArrayElements(result, result_bytes, 0);
+
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ jclass cryptopp_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Cryptopp");
+ jfieldID type_id = env->GetFieldID(cryptopp_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
+ Integer private_key_x((byte *) privkey_data, (size_t) privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
+
+ jbyteArray result = NULL;
+
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+ if (type_str.find("SHA1") != std::string::npos) {
+ result = sign_message<EC2N, SHA1>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ result = sign_message<EC2N, SHA224>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ result = sign_message<EC2N, SHA256>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ result = sign_message<EC2N, SHA384>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ result = sign_message<EC2N, SHA512>(env, *ec2n_group, data, private_key_x);
+ }
+ } else {
+ if (type_str.find("SHA1") != std::string::npos) {
+ result = sign_message<ECP, SHA1>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ result = sign_message<ECP, SHA224>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ result = sign_message<ECP, SHA256>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ result = sign_message<ECP, SHA384>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ result = sign_message<ECP, SHA512>(env, *ecp_group, data, private_key_x);
+ }
+ }
+
+ return result;
+}
+
+template <class EC, class H>
+jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray data, jbyteArray signature, jbyteArray pubkey) {
+ typename EC::Point pkey_point;
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ group.GetCurve().DecodePoint(pkey_point, (byte *)pubkey_data, pubkey_length);
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ typename ECDSA<EC, H>::PublicKey pkey;
+ pkey.Initialize(group, pkey_point);
+ typename ECDSA<EC, H>::Verifier verifier(pkey);
+
+ size_t bit_length = group.GetCurve().GetField().MaxElementBitLength();
+ size_t bytes = (bit_length + 7)/8;
+
+ jsize sig_length = env->GetArrayLength(signature);
+ jbyte *sig_bytes = env->GetByteArrayElements(signature, NULL);
+
+ byte sig[bytes * 2];
+ size_t sig_len = DSAConvertSignatureFormat(sig, bytes * 2, DSA_P1363, (byte *)sig_bytes, sig_length, DSA_DER);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+
+ jsize data_length = env->GetArrayLength(data);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ native_timing_start();
+ bool result = verifier.VerifyMessage((byte *)data_bytes, data_length, sig, sig_len);
+ native_timing_stop();
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jclass cryptopp_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Cryptopp");
+ jfieldID type_id = env->GetFieldID(cryptopp_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+
+ if (type_str.find("SHA1") != std::string::npos) {
+ return verify_message<EC2N, SHA1>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ return verify_message<EC2N, SHA224>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ return verify_message<EC2N, SHA256>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ return verify_message<EC2N, SHA384>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ return verify_message<EC2N, SHA512>(env, *ec2n_group, data, signature, pubkey);
+ }
+ } else {
+ if (type_str.find("SHA1") != std::string::npos) {
+ return verify_message<ECP, SHA1>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ return verify_message<ECP, SHA224>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ return verify_message<ECP, SHA256>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ return verify_message<ECP, SHA384>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ return verify_message<ECP, SHA512>(env, *ecp_group, data, signature, pubkey);
+ }
+ }
+ // unreachable
+ return JNI_FALSE;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
new file mode 100644
index 0000000..5d29d2c
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
@@ -0,0 +1,623 @@
+#include "native.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <gcrypt.h>
+#include "c_utils.h"
+#include "c_timing.h"
+
+static jclass provider_class;
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_createProvider(JNIEnv *env, jobject this){
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Gcrypt");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ const char *running_with = gcry_check_version(GCRYPT_VERSION);
+ if (!running_with) {
+ return NULL;
+ }
+ char full_name[strlen("libgcrypt ") + strlen(running_with) + 1];
+ strcpy(full_name, "libgcrypt ");
+ strcat(full_name, running_with);
+ jstring name = (*env)->NewStringUTF(env, full_name);
+ double version = strtod(running_with, NULL);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Gcrypt_setup(JNIEnv *env, jobject this) {
+ gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
+ //gcry_control(GCRYCTL_SET_DEBUG_FLAGS, 1);
+ gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, this, "EC", "Gcrypt");
+ ADD_KA(env, this, "ECDH", "GcryptECDH");
+ ADD_SIG(env, this, "NONEwithECDSA", "GcryptECDSAwithNONE");
+ ADD_SIG(env, this, "SHA1withECDSA", "GcryptECDSAwithSHA1");
+ ADD_SIG(env, this, "SHA224withECDSA", "GcryptECDSAwithSHA224");
+ ADD_SIG(env, this, "SHA256withECDSA", "GcryptECDSAwithSHA256");
+ ADD_SIG(env, this, "SHA384withECDSA", "GcryptECDSAwithSHA384");
+ ADD_SIG(env, this, "SHA512withECDSA", "GcryptECDSAwithSHA512");
+ ADD_SIG(env, this, "SHA1withECDDSA", "GcryptECDDSAwithSHA1");
+ ADD_SIG(env, this, "SHA224withECDDSA", "GcryptECDDSAwithSHA224");
+ ADD_SIG(env, this, "SHA256withECDDSA", "GcryptECDDSAwithSHA256");
+ ADD_SIG(env, this, "SHA384withECDDSA", "GcryptECDDSAwithSHA384");
+ ADD_SIG(env, this, "SHA512withECDDSA", "GcryptECDDSAwithSHA512");
+
+ init_classes(env, "Gcrypt");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getCurves(JNIEnv *env, jobject this) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ const char *name;
+ unsigned int nbits;
+
+ for (size_t i = 0; (name = gcry_pk_get_curve(NULL, i, &nbits)); i++){
+ jstring curve_name = (*env)->NewStringUTF(env, name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize) {
+ const char *name;
+ unsigned int nbits;
+
+ for (size_t i = 0; (name = gcry_pk_get_curve(NULL, i, &nbits)); i++){
+ if (nbits == keysize) {
+ return JNI_TRUE;
+ }
+ }
+
+ return JNI_FALSE;
+}
+
+/*
+static void print_sexp(gcry_sexp_t sexp) {
+ size_t len = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+ char string[len];
+ gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, string, len);
+ printf("%s\n", string);
+ fflush(stdout);
+}
+
+static void print_chrray(unsigned char *arr, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ printf("%02x,", ((unsigned char) arr[i] & 0xff));
+ }
+ printf("\n");
+}
+*/
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported(JNIEnv *env, jobject this, jobject params) {
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return JNI_FALSE;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ gcry_sexp_t curve_sexp;
+ gcry_sexp_build(&curve_sexp, NULL, "(public-key (ecc (curve %s)))", utf_name);
+ unsigned int nbits;
+ const char *ret_name = gcry_pk_get_curve(curve_sexp, 0, &nbits);
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ gcry_sexp_release(curve_sexp);
+ return ret_name ? JNI_TRUE : JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static gcry_mpi_t bytearray_to_mpi(JNIEnv *env, jbyteArray array) {
+ if (!array) {
+ return NULL;
+ }
+
+ gcry_mpi_t result;
+
+ size_t length = (*env)->GetArrayLength(env, array);
+ jbyte data[length + 1];
+ data[0] = 0;
+ (*env)->GetByteArrayRegion(env, array, 0, length, data + 1);
+ gcry_mpi_scan(&result, GCRYMPI_FMT_STD, data, length + 1, NULL);
+ return result;
+}
+
+static jbyteArray mpi_to_bytearray0(JNIEnv *env, gcry_mpi_t mpi, size_t start, size_t len) {
+ if (!mpi) {
+ return NULL;
+ }
+
+ size_t mpi_len = 0;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &mpi_len, mpi);
+ if (start >= mpi_len) {
+ return NULL;
+ }
+ if (start + len > mpi_len || len == 0) {
+ len = mpi_len - start;
+ }
+ unsigned char buff[mpi_len];
+ gcry_mpi_print(GCRYMPI_FMT_USG, buff, mpi_len, NULL, mpi);
+ jbyteArray bytes = (*env)->NewByteArray(env, len);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ memcpy(data, buff + start, len);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ return bytes;
+}
+
+static jbyteArray mpi_to_bytearray(JNIEnv *env, gcry_mpi_t mpi) {
+ return mpi_to_bytearray0(env, mpi, 0, 0);
+}
+
+static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) {
+ if (!mpi) {
+ return NULL;
+ }
+
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ jbyteArray bytes = mpi_to_bytearray(env, mpi);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static gcry_mpi_t biginteger_to_mpi(JNIEnv *env, jobject bigint) {
+ if (!bigint) {
+ return NULL;
+ }
+
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
+ return bytearray_to_mpi(env, byte_array);
+}
+
+static jint mpi_to_jint(gcry_mpi_t mpi) {
+ jint result = 0;
+ unsigned long nbits = gcry_mpi_get_nbits(mpi);
+ int max_bits = sizeof(jint) * 8;
+ for (size_t i = 0; i < nbits && i < max_bits; ++i) {
+ if (gcry_mpi_test_bit(mpi, nbits - i - 1)) {
+ result = ((result << 1) | 1);
+ } else {
+ result = (result << 1);
+ }
+ }
+ return result;
+}
+
+static jobject buff_to_ecpoint(JNIEnv *env, gcry_buffer_t buff) {
+ jint coord_size = (buff.len - 1) / 2;
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+
+ jbyteArray x_bytes = (*env)->NewByteArray(env, coord_size);
+ jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL);
+ memcpy(x_data, ((char *) buff.data) + 1, coord_size);
+ (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0);
+ jobject xi = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, x_bytes);
+
+ jbyteArray y_bytes = (*env)->NewByteArray(env, coord_size);
+ jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL);
+ memcpy(y_data, ((char *) buff.data) + 1 + coord_size, coord_size);
+ (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0);
+ jobject yi = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, y_bytes);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ return (*env)->NewObject(env, point_class, point_init, xi, yi);
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, gcry_sexp_t key) {
+ jobject result = NULL;
+ gcry_mpi_t p, a, b, n, h;
+ gcry_buffer_t g = {0};
+ gcry_error_t err = gcry_sexp_extract_param(key, "ecc", "pab&g+nh", &p, &a, &b, &g, &n, &h, NULL);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error exporting domain parameters. Error: %ui", gcry_err_code(err));
+ goto end;
+ }
+
+ jobject pi = mpi_to_biginteger(env, p);
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, pi);
+
+ jobject ai = mpi_to_biginteger(env, a);
+ jobject bi = mpi_to_biginteger(env, b);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, ai, bi);
+
+ jobject gen = buff_to_ecpoint(env, g);
+
+ jobject order = mpi_to_biginteger(env, n);
+ jint cofactor = mpi_to_jint(h);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ result = (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, gen, order, cofactor);
+
+end:
+ gcry_mpi_release(p);
+ gcry_mpi_release(a);
+ gcry_mpi_release(b);
+ gcry_free(g.data);
+ gcry_mpi_release(n);
+ gcry_mpi_release(h);
+ return result;
+}
+
+static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) {
+ jobject result = NULL;
+ gcry_sexp_t key_sexp;
+
+ native_timing_start();
+ gcry_error_t err = gcry_pk_genkey(&key_sexp, gen_sexp);
+ native_timing_stop();
+
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error generating key. Error: %ui", gcry_err_code(err));
+ goto release_sexp;
+ }
+ gcry_sexp_t pkey = gcry_sexp_find_token(key_sexp, "public-key", 0);
+ gcry_sexp_t skey = gcry_sexp_find_token(key_sexp, "private-key", 0);
+
+ jobject ec_param_spec = create_ec_param_spec(env, skey);
+ if (!ec_param_spec) {
+ goto release_keypair;
+ }
+
+ gcry_buffer_t q = {0};
+ gcry_mpi_t d;
+ err = gcry_sexp_extract_param(skey, "ecc", "&q+d", &q, &d, NULL);
+
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, q.size);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ memcpy(key_pub, q.data, q.size);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ size_t priv_len = 0;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &priv_len, d);
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, priv_len);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char *) key_priv, priv_len, NULL, d);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ result = (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+
+ gcry_mpi_release(d);
+ gcry_free(q.data);
+
+release_keypair:
+ gcry_sexp_release(pkey);
+ gcry_sexp_release(skey);
+release_sexp:
+ gcry_sexp_release(key_sexp);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random) {
+ gcry_sexp_t gen_sexp;
+ gcry_sexp_build(&gen_sexp, NULL, "(genkey (ecc (flags no-keytest param) (nbits %d)))", keysize);
+
+ jobject result = generate_from_sexp(env, gen_sexp);
+ gcry_sexp_release(gen_sexp);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return NULL;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ gcry_sexp_t gen_sexp;
+ gcry_sexp_build(&gen_sexp, NULL, "(genkey (ecc (flags no-keytest param) (curve %s)))", utf_name);
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ jobject result = generate_from_sexp(env, gen_sexp);
+ gcry_sexp_release(gen_sexp);
+ return result;
+ } else {
+ return NULL;
+ }
+}
+
+static gcry_sexp_t create_key(JNIEnv *env, jobject ec_param_spec, const char *key_fmt, gcry_mpi_t q, gcry_mpi_t d) {
+ gcry_mpi_t p, a, b, g, n, h;
+
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, ec_param_spec, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ jint bytes = (bits + 7) / 8;
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject big_a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+ a = biginteger_to_mpi(env, big_a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject big_b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+ b = biginteger_to_mpi(env, big_b);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject big_p = (*env)->CallObjectMethod(env, field, get_p);
+ p = biginteger_to_mpi(env, big_p);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g_point = (*env)->CallObjectMethod(env, ec_param_spec, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g_point, get_x);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g_point, get_y);
+
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray gx_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gx, to_byte_array);
+ size_t gx_len = (*env)->GetArrayLength(env, gx_bytes);
+ jbyteArray gy_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gy, to_byte_array);
+ size_t gy_len = (*env)->GetArrayLength(env, gy_bytes);
+ unsigned char g_data[1 + 2 * bytes];
+ g_data[0] = 0x04;
+ jbyte *gx_data = (*env)->GetByteArrayElements(env, gx_bytes, NULL);
+ memcpy(g_data + 1, gx_data + (gx_len - bytes), bytes);
+ (*env)->ReleaseByteArrayElements(env, gx_bytes, gx_data, JNI_ABORT);
+ jbyte *gy_data = (*env)->GetByteArrayElements(env, gy_bytes, NULL);
+ memcpy(g_data + 1 + bytes, gy_data + (gy_len - bytes), bytes);
+ (*env)->ReleaseByteArrayElements(env, gy_bytes, gy_data, JNI_ABORT);
+
+ gcry_mpi_scan(&g, GCRYMPI_FMT_USG, g_data, 1 + 2 * bytes, NULL);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject big_n = (*env)->CallObjectMethod(env, ec_param_spec, get_n);
+ n = biginteger_to_mpi(env, big_n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint jh = (*env)->CallIntMethod(env, ec_param_spec, get_h);
+ h = gcry_mpi_set_ui(NULL, jh);
+
+ gcry_sexp_t inner = NULL;
+ if (q && d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (q %M) (d %M))", p, a, b, g, n, h, q, d, NULL);
+ } else if (q && !d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (q %m))", p, a, b, g, n, h, q, NULL);
+ } else if (!q && d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (d %m))", p, a, b, g, n, h, d, NULL);
+ }
+ gcry_sexp_t result;
+ gcry_sexp_build(&result, NULL, key_fmt, inner, NULL);
+ gcry_sexp_release(inner);
+ return result;
+}
+
+static gcry_sexp_t create_pubkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey) {
+ gcry_mpi_t q = bytearray_to_mpi(env, pubkey);
+ gcry_sexp_t result = create_key(env, ec_param_spec, "(public-key %S)", q, NULL);
+ gcry_mpi_release(q);
+ return result;
+}
+
+static gcry_sexp_t create_privkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey, jbyteArray privkey) {
+ gcry_mpi_t q = bytearray_to_mpi(env, pubkey);
+ gcry_mpi_t d = bytearray_to_mpi(env, privkey);
+ gcry_sexp_t result = create_key(env, ec_param_spec, "(private-key %S)", q, d);
+ gcry_mpi_release(q);
+ gcry_mpi_release(d);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jbyteArray result = NULL;
+ gcry_sexp_t pub = create_pubkey(env, params, pubkey);
+ gcry_mpi_t priv = bytearray_to_mpi(env, privkey);
+
+ gcry_sexp_t enc_sexp;
+ gcry_sexp_build(&enc_sexp, NULL, "(data (flags raw) (value %M))", priv, NULL);
+ gcry_sexp_t res_sexp;
+ // TODO: figure out why ecc_encrypt_raw takes signed representation.. Nobody uses that., everybody uses unsigned reduced mod p.
+
+ native_timing_start();
+ gcry_error_t err = gcry_pk_encrypt(&res_sexp, enc_sexp, pub);
+ native_timing_stop();
+
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDH. Error: %ui", gcry_err_code(err));
+ goto end;
+ }
+
+ gcry_mpi_t derived;
+ err = gcry_sexp_extract_param(res_sexp, NULL, "s", &derived, NULL);
+
+ size_t derived_bytes;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &derived_bytes, derived);
+ size_t coord_bytes = (derived_bytes - 1) / 2;
+ result = mpi_to_bytearray0(env, derived, 1, coord_bytes);
+
+ gcry_mpi_release(derived);
+end:
+ gcry_sexp_release(enc_sexp);
+ gcry_sexp_release(res_sexp);
+ gcry_sexp_release(pub);
+ gcry_mpi_release(priv);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+static int starts_with(const char *whole, const char *prefix) {
+ return !strncmp(whole, prefix, strlen(prefix));
+}
+
+static int get_hash_algo(const char *sig_type) {
+ if (starts_with(sig_type, "SHA1")) {
+ return GCRY_MD_SHA1;
+ } else if (starts_with(sig_type, "SHA224")) {
+ return GCRY_MD_SHA224;
+ } else if (starts_with(sig_type, "SHA256")) {
+ return GCRY_MD_SHA256;
+ } else if (starts_with(sig_type, "SHA384")) {
+ return GCRY_MD_SHA384;
+ } else if (starts_with(sig_type, "SHA512")) {
+ return GCRY_MD_SHA512;
+ } else {
+ return GCRY_MD_NONE;
+ }
+}
+
+static const char *get_sig_algo(const char *sig_type) {
+ const char *start = strstr(sig_type, "with") + strlen("with");
+ if (starts_with(start, "ECDSA")) {
+ return NULL;
+ } else if (starts_with(start, "ECDDSA")) {
+ return "rfc6979";
+ } else {
+ return NULL;
+ }
+}
+
+static void get_sign_data_sexp(JNIEnv *env, gcry_sexp_t *result, jobject this, jbyteArray data) {
+ jclass sig_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Gcrypt");
+ jfieldID type_id = (*env)->GetFieldID(env, sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring)(*env)->GetObjectField(env, this, type_id);
+ const char* type_data = (*env)->GetStringUTFChars(env, type, NULL);
+ int hash_algo = get_hash_algo(type_data);
+ const char *sig_algo = get_sig_algo(type_data);
+ const char *with = strstr(type_data, "with");
+ char hash_name[with - type_data + 1];
+ memcpy(hash_name, type_data, with - type_data);
+ for (size_t i = 0; i < with - type_data; ++i) {
+ hash_name[i] = tolower(hash_name[i]);
+ }
+ hash_name[with - type_data] = 0;
+ (*env)->ReleaseStringUTFChars(env, type, type_data);
+
+ if (hash_algo == GCRY_MD_NONE) {
+ gcry_mpi_t data_mpi = bytearray_to_mpi(env, data);
+ gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", data_mpi);
+ gcry_mpi_release(data_mpi);
+ } else {
+ unsigned int hash_len = gcry_md_get_algo_dlen(hash_algo);
+ size_t data_len = (*env)->GetArrayLength(env, data);
+ jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL);
+ unsigned char out_hash[hash_len];
+ gcry_md_hash_buffer(hash_algo, out_hash, data_bytes, data_len);
+ (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT);
+ gcry_mpi_t hash_mpi;
+ gcry_mpi_scan(&hash_mpi, GCRYMPI_FMT_USG, out_hash, hash_len, NULL);
+ if (!sig_algo) {
+ gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", hash_mpi);
+ } else {
+ gcry_sexp_build(result, NULL, "(data (flags %s param) (hash %s %M))", sig_algo, hash_name, hash_mpi);
+ }
+ gcry_mpi_release(hash_mpi);
+ }
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ jbyteArray result = NULL;
+ gcry_sexp_t priv_sexp = create_privkey(env, params, NULL, privkey);
+
+ gcry_sexp_t data_sexp;
+ get_sign_data_sexp(env, &data_sexp, this, data);
+
+ gcry_sexp_t res_sexp;
+ native_timing_start();
+ gcry_error_t err = gcry_pk_sign(&res_sexp, data_sexp, priv_sexp);
+ native_timing_stop();
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDSA. Error: %ui", gcry_err_code(err));
+ goto release_init;
+ }
+
+ gcry_buffer_t r_buf = {0};
+ gcry_buffer_t s_buf = {0};
+ err = gcry_sexp_extract_param(res_sexp, "ecdsa", "&rs", &r_buf, &s_buf, NULL);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error extracting ECDSA output. Error: %ui", gcry_err_code(err));
+ goto release_res;
+ }
+ result = asn1_der_encode(env, r_buf.data, r_buf.len, s_buf.data, s_buf.len);
+
+ gcry_free(r_buf.data);
+ gcry_free(s_buf.data);
+release_res:
+ gcry_sexp_release(res_sexp);
+release_init:
+ gcry_sexp_release(priv_sexp);
+ gcry_sexp_release(data_sexp);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify(JNIEnv *env, jobject this, jbyteArray sig, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jboolean result = JNI_FALSE;
+ gcry_sexp_t pub_sexp = create_pubkey(env, params, pubkey);
+
+ gcry_sexp_t data_sexp;
+ get_sign_data_sexp(env, &data_sexp, this, data);
+
+ size_t r_len, s_len;
+ jbyte *r_data, *s_data;
+ bool decode = asn1_der_decode(env, sig, &r_data, &r_len, &s_data, &s_len);
+ if (!decode) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error decoding sig.");
+ goto release_init;
+ }
+
+ gcry_mpi_t r_mpi, s_mpi;
+ gcry_mpi_scan(&r_mpi, GCRYMPI_FMT_USG, r_data, r_len, NULL);
+ gcry_mpi_scan(&s_mpi, GCRYMPI_FMT_USG, s_data, s_len, NULL);
+ free(r_data);
+ free(s_data);
+
+ gcry_sexp_t sig_sexp;
+ gcry_sexp_build(&sig_sexp, NULL, "(sig-val (ecdsa (r %M) (s %M)))", r_mpi, s_mpi);
+
+ native_timing_start();
+ gcry_error_t err = gcry_pk_verify(sig_sexp, data_sexp, pub_sexp);
+ native_timing_stop();
+
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error verif sig.");
+ goto release_init;
+ }
+ } else {
+ result = JNI_TRUE;
+ }
+
+release_init:
+ gcry_sexp_release(pub_sexp);
+ gcry_sexp_release(data_sexp);
+ return result;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/ippcp.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/ippcp.c
new file mode 100644
index 0000000..98a4c36
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/ippcp.c
@@ -0,0 +1,698 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "native.h"
+
+#include <ippcp.h>
+
+#include "c_timing.h"
+#include "c_utils.h"
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdio.h>
+#include <time.h>
+
+#define USE_SPEEDUP 1
+#define VALIDATE_CURVE 1
+#define VALIDATE_POINT 1
+
+static IppsPRNGState *prng_state;
+static jclass provider_class;
+
+/* This needs to be specified in this way because ippcp does not offer functionality to retrieve
+ information about supported curves in any way. */
+typedef struct {
+ const char name[128];
+ IppECCType id;
+ int size;
+ IppStatus (*context_size_func)(int *);
+ IppStatus (*init_func)(IppsECCPState *);
+ IppStatus (*set_func)(IppsECCPState *);
+ IppStatus (*precomp_func)(IppsECCPState *);
+} ippcp_curve;
+
+static const ippcp_curve CURVES[] = {
+ {"secp112r1", IppECCPStd112r1, 112, NULL, NULL, NULL, NULL},
+ {"secp112r2", IppECCPStd112r2, 112, NULL, NULL, NULL, NULL},
+ {"secp128r1", IppECCPStd128r1, 128, ippsECCPGetSizeStd128r1, ippsECCPInitStd128r1, ippsECCPSetStd128r1, NULL},
+ {"secp128r2", IppECCPStd128r2, 128, ippsECCPGetSizeStd128r2, ippsECCPInitStd128r2, ippsECCPSetStd128r2, NULL},
+ {"secp160r1", IppECCPStd160r1, 160, NULL, NULL, NULL, NULL},
+ {"secp160r2", IppECCPStd160r2, 160, NULL, NULL, NULL, NULL},
+ {"secp192r1", IppECCPStd192r1, 192, ippsECCPGetSizeStd192r1, ippsECCPInitStd192r1, ippsECCPSetStd192r1, ippsECCPBindGxyTblStd192r1},
+ {"secp224r1", IppECCPStd224r1, 224, ippsECCPGetSizeStd224r1, ippsECCPInitStd224r1, ippsECCPSetStd224r1, ippsECCPBindGxyTblStd224r1},
+ {"secp256r1", IppECCPStd256r1, 256, ippsECCPGetSizeStd256r1, ippsECCPInitStd256r1, ippsECCPSetStd256r1, ippsECCPBindGxyTblStd256r1},
+ {"secp384r1", IppECCPStd384r1, 384, ippsECCPGetSizeStd384r1, ippsECCPInitStd384r1, ippsECCPSetStd384r1, ippsECCPBindGxyTblStd384r1},
+ {"secp521r1", IppECCPStd521r1, 521, ippsECCPGetSizeStd521r1, ippsECCPInitStd521r1, ippsECCPSetStd521r1, ippsECCPBindGxyTblStd521r1}};
+
+static const int NUM_CURVES = sizeof(CURVES) / sizeof(ippcp_curve);
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_IppcpLib_createProvider(JNIEnv *env, jobject this) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Ippcp");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ const IppLibraryVersion *lib = ippcpGetLibVersion();
+ jstring name = (*env)->NewStringUTF(env, lib->Name);
+ double version = (double)lib->major + ((double)lib->minor / 10);
+ jstring info = (*env)->NewStringUTF(env, lib->Version);
+
+ // printf("%s\n%s\n%d.%d.%d.%d\n", lib->Name, lib->Version, lib->major, lib->minor, lib->majorBuild, lib->build);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, info);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Ippcp_setup(JNIEnv *env, jobject this) {
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, this, "EC", "Ippcp");
+ ADD_KA(env, this, "ECDH", "IppcpECDH");
+ ADD_SIG(env, this, "NONEwithECDSA", "IppcpECDSAwithNONE");
+
+ /* Init the PRNG. */
+ int prng_size;
+ ippsPRNGGetSize(&prng_size);
+ prng_state = malloc(prng_size);
+ ippsPRNGInit(160, prng_state);
+ /* We need to manually seed the PRNG, let's hope that everyone using ippcp does this.
+ Otherwise: nonce reuse in ECDSA, whoops! */
+ int seed_len = 8;
+ Ipp32u seed[seed_len];
+ IppStatus res = ippsTRNGenRDSEED(seed, sizeof(seed) * 8, NULL);
+ if (res != ippStsNoErr) {
+ res = ippsPRNGenRDRAND(seed, sizeof(seed) * 8, NULL);
+ }
+ if (res != ippStsNoErr) {
+ FILE *urandom = fopen("/dev/urandom", "rb");
+ if (urandom) {
+ size_t read = 0;
+ while (read < sizeof(seed)) {
+ read += fread(((uint8_t *)&seed) + read, 1, sizeof(seed) - read, urandom);
+ }
+ fclose(urandom);
+ res = ippStsNoErr;
+ }
+ }
+ if (res != ippStsNoErr) {
+ struct timespec t;
+ if (!clock_gettime(CLOCK_REALTIME, &t)) {
+ memcpy(seed, &t.tv_nsec, sizeof(t.tv_nsec) > sizeof(seed) ? sizeof(seed) : sizeof(t.tv_nsec));
+ } else {
+ time_t tim = time(NULL);
+ memcpy(seed, &tim, sizeof(time_t) > sizeof(seed) ? sizeof(seed) : sizeof(time_t));
+ }
+ }
+ int bn_size;
+ ippsBigNumGetSize(seed_len, &bn_size);
+ uint8_t bn_buf[bn_size];
+ IppsBigNumState *bn = (IppsBigNumState *)bn_buf;
+ ippsBigNumInit(seed_len, bn);
+ ippsSet_BN(IppsBigNumPOS, seed_len, seed, bn);
+ ippsPRNGSetSeed(bn, prng_state);
+
+ init_classes(env, "Ippcp");
+}
+
+static IppStatus prng_wrapper(Ipp32u *pRand, int nBits, void *pCtx) {
+ native_timing_pause();
+ IppStatus result = ippsPRNGen(pRand, nBits, pCtx);
+ native_timing_restart();
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_IppcpLib_getCurves(JNIEnv *env, jobject this) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ for (size_t i = 0; i < NUM_CURVES; ++i) {
+ jstring curve_name = (*env)->NewStringUTF(env, CURVES[i].name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_keysizeSupported(JNIEnv *env,
+ jobject this,
+ jint keysize) {
+ for (size_t i = 0; i < NUM_CURVES; ++i) {
+ if (CURVES[i].size == keysize) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_paramsSupported(JNIEnv *env,
+ jobject this,
+ jobject params) {
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+ if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ for (size_t i = 0; i < NUM_CURVES; ++i) {
+ if (strcasecmp(utf_name, CURVES[i].name) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+
+static IppsECCPPointState *new_point(int size) {
+ int point_size;
+ ippsECCPPointGetSize(size, &point_size);
+ IppsECCPPointState *point = malloc(point_size);
+ ippsECCPPointInit(size, point);
+ return point;
+}
+
+static IppsBigNumState *new_bn(int bits) {
+ int bn_size;
+ int len = ((bits + 7) / 8) / sizeof(Ipp32u);
+ ippsBigNumGetSize(len, &bn_size);
+ IppsBigNumState *bn = malloc(bn_size);
+ ippsBigNumInit(len, bn);
+ return bn;
+}
+
+static void bn_get(IppsBigNumState *bn, uint8_t *buf, int lsb) {
+ int size;
+ ippsGetSize_BN(bn, &size);
+ size *= sizeof(Ipp32u);
+ uint8_t data[size];
+ ippsGetOctString_BN(data, size, bn);
+ memcpy(buf, data + (size - lsb), lsb);
+}
+
+static jobject bn_to_biginteger(JNIEnv *env, const IppsBigNumState *bn) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ int bn_size;
+ ippsGetSize_BN(bn, &bn_size);
+ bn_size *= sizeof(Ipp32u);
+ jbyteArray bytes = (*env)->NewByteArray(env, bn_size);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ ippsGetOctString_BN((Ipp8u *) data, bn_size, bn);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static IppsBigNumState *biginteger_to_bn(JNIEnv *env, jobject bigint) {
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
+ jsize byte_length = (*env)->GetArrayLength(env, byte_array);
+ jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ IppsBigNumState *result = new_bn(byte_length * 8);
+ ippsSetOctString_BN((Ipp8u *) byte_data, byte_length, result);
+ (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+/*
+static void biginteger_print(JNIEnv *env, jobject bigint) {
+ jmethodID to_string = (*env)->GetMethodID(env, biginteger_class, "toString", "(I)Ljava/lang/String;");
+ jstring big_string = (*env)->CallObjectMethod(env, bigint, to_string, (jint) 16);
+
+ jsize len = (*env)->GetStringUTFLength(env, big_string);
+ char raw_string[len + 1];
+ raw_string[len] = 0;
+ (*env)->GetStringUTFRegion(env, big_string, 0, len, raw_string);
+ printf("%s\n", raw_string);
+ fflush(stdout);
+}
+*/
+
+static IppsECCPState *create_curve(JNIEnv *env, jobject params, int *keysize) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+ IppsBigNumState *p_bn = biginteger_to_bn(env, p);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, curve, get_a);
+ IppsBigNumState *a_bn = biginteger_to_bn(env, a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, curve, get_b);
+ IppsBigNumState *b_bn = biginteger_to_bn(env, b);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+ IppsBigNumState *gx_bn = biginteger_to_bn(env, gx);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+ IppsBigNumState *gy_bn = biginteger_to_bn(env, gy);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ IppsBigNumState *n_bn = biginteger_to_bn(env, n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = (*env)->CallIntMethod(env, params, get_h);
+
+ if (keysize) {
+ *keysize = bits;
+ }
+
+ int size;
+ ippsECCPGetSize(bits, &size);
+ IppsECCPState *result = malloc(size);
+ ippsECCPInit(bits, result);
+ ippsECCPSet(p_bn, a_bn, b_bn, gx_bn, gy_bn, n_bn, h, result);
+
+ return result;
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, int keysize, IppsECCPState *curve) {
+ IppsBigNumState *p_bn = new_bn(keysize);
+ IppsBigNumState *a_bn = new_bn(keysize);
+ IppsBigNumState *b_bn = new_bn(keysize);
+ int ord_bits;
+ ippsECCPGetOrderBitSize(&ord_bits, curve);
+ IppsBigNumState *gx_bn = new_bn(ord_bits);
+ IppsBigNumState *gy_bn = new_bn(ord_bits);
+ IppsBigNumState *order_bn = new_bn(ord_bits);
+ int cofactor;
+
+ ippsECCPGet(p_bn, a_bn, b_bn, gx_bn, gy_bn, order_bn, &cofactor, curve);
+
+ jobject p = bn_to_biginteger(env, p_bn);
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p);
+ free(p_bn);
+
+ jobject a = bn_to_biginteger(env, a_bn);
+ jobject b = bn_to_biginteger(env, b_bn);
+ free(a_bn);
+ free(b_bn);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a, b);
+
+ jobject gx = bn_to_biginteger(env, gx_bn);
+ jobject gy = bn_to_biginteger(env, gy_bn);
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy);
+ free(gx_bn);
+ free(gy_bn);
+
+ jobject n = bn_to_biginteger(env, order_bn);
+ free(order_bn);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, cofactor);
+}
+
+static jobject generate_from_curve(JNIEnv *env, int keysize, IppsECCPState *curve) {
+ if (VALIDATE_CURVE) {
+ IppECResult validation;
+ ippsECCPValidate(50, &validation, curve, ippsPRNGen, prng_state);
+ if (validation != ippECValid) {
+ throw_new(env, "java/security/GeneralSecurityException", ippsECCGetResultString(validation));
+ return NULL;
+ }
+ }
+
+ IppsECCPPointState *point = new_point(keysize);
+
+ int ord_bits;
+ ippsECCPGetOrderBitSize(&ord_bits, curve);
+ int ord_bytes = (ord_bits + 7) / 8;
+ IppsBigNumState *secret = new_bn(ord_bits);
+
+ native_timing_start();
+ IppStatus err = ippsECCPGenKeyPair(secret, point, curve, prng_wrapper, prng_state);
+ native_timing_stop();
+
+ if (err != ippStsNoErr) {
+ throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err));
+ free(point);
+ free(secret);
+ return NULL;
+ }
+
+ int coord_bytes = (keysize + 7) / 8;
+ IppsBigNumState *x = new_bn(keysize);
+ IppsBigNumState *y = new_bn(keysize);
+
+ ippsECCPGetPoint(x, y, point, curve);
+
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, 2 * coord_bytes + 1);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ pub_data[0] = 0x04;
+ bn_get(x, (uint8_t *) (pub_data + 1), coord_bytes);
+ bn_get(y, (uint8_t *) (pub_data + 1 + coord_bytes), coord_bytes);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, pub_data, 0);
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, ord_bytes);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ bn_get(secret, (uint8_t *) priv_data, ord_bytes);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, priv_data, 0);
+
+ free(point);
+ free(secret);
+ free(x);
+ free(y);
+
+ jobject ec_param_spec = create_ec_param_spec(env, keysize, curve);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+static jobject generate_from_curve_info(JNIEnv *env, const ippcp_curve *curve_info) {
+ int context_size;
+ if (curve_info->context_size_func) {
+ curve_info->context_size_func(&context_size);
+ } else {
+ ippsECCPGetSize(curve_info->size, &context_size);
+ }
+ uint8_t curve_buf[context_size];
+ IppsECCPState *curve = (IppsECCPState *)curve_buf;
+ if (curve_info->init_func) {
+ curve_info->init_func(curve);
+ } else {
+ ippsECCPInit(curve_info->size, curve);
+ }
+ if (curve_info->set_func) {
+ curve_info->set_func(curve);
+ } else {
+ ippsECCPSetStd(curve_info->id, curve);
+ }
+ if (USE_SPEEDUP && curve_info->precomp_func) {
+ curve_info->precomp_func(curve);
+ }
+ return generate_from_curve(env, curve_info->size, curve);
+}
+
+JNIEXPORT jobject JNICALL
+Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_generate__ILjava_security_SecureRandom_2(JNIEnv *env,
+ jobject this,
+ jint keysize,
+ jobject random) {
+ for (size_t i = 0; i < NUM_CURVES; ++i) {
+ if (CURVES[i].size == keysize) {
+ return generate_from_curve_info(env, &CURVES[i]);
+ }
+ }
+ return NULL;
+}
+
+JNIEXPORT jobject JNICALL
+Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(
+ JNIEnv *env, jobject this, jobject params, jobject random) {
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ int keysize;
+ IppsECCPState *curve = create_curve(env, params, &keysize);
+ jobject result = generate_from_curve(env, keysize, curve);
+ free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const ippcp_curve *curve_info;
+ for (size_t i = 0; i < NUM_CURVES; ++i) {
+ if (strcasecmp(utf_name, CURVES[i].name) == 0) {
+ curve_info = &CURVES[i];
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return generate_from_curve_info(env, curve_info);
+ } else {
+ return NULL;
+ }
+}
+
+static IppsECCPPointState *bytearray_to_pubkey(JNIEnv *env, jbyteArray pubkey, jint keysize, IppsECCPState *curve) {
+ IppsBigNumState *x_bn = new_bn(keysize);
+ IppsBigNumState *y_bn = new_bn(keysize);
+
+ jint coord_size = (keysize + 7) / 8;
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL);
+ ippsSetOctString_BN((Ipp8u *) (pub_data + 1), coord_size, x_bn);
+ ippsSetOctString_BN((Ipp8u *) (pub_data + 1 + coord_size), coord_size, y_bn);
+ (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+
+ IppsECCPPointState *pub = new_point(keysize);
+ ippsECCPSetPoint(x_bn, y_bn, pub, curve);
+ free(x_bn);
+ free(y_bn);
+ return pub;
+}
+
+static IppsBigNumState *bytearray_to_privkey(JNIEnv *env, jbyteArray privkey, IppsECCPState *curve) {
+ int ord_bits;
+ ippsECCPGetOrderBitSize(&ord_bits, curve);
+ IppsBigNumState *priv_bn = new_bn(ord_bits);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL);
+ ippsSetOctString_BN((Ipp8u *) priv_data, (*env)->GetArrayLength(env, privkey), priv_bn);
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ return priv_bn;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Ippcp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jint coord_size = ((*env)->GetArrayLength(env, pubkey) - 1) / 2;
+ jint keysize;
+ IppsECCPState *curve = create_curve(env, params, &keysize);
+
+ if (VALIDATE_CURVE) {
+ IppECResult validation;
+ ippsECCPValidate(50, &validation, curve, ippsPRNGen, prng_state);
+ if (validation != ippECValid) {
+ throw_new(env, "java/security/GeneralSecurityException", ippsECCGetResultString(validation));
+ free(curve);
+ return NULL;
+ }
+ }
+ IppsECCPPointState *pub = bytearray_to_pubkey(env, pubkey, keysize, curve);
+
+ if (VALIDATE_POINT) {
+ IppECResult validation;
+ ippsECCPCheckPoint(pub, &validation, curve);
+ if (validation != ippECValid) {
+ throw_new(env, "java/security/GeneralSecurityException", ippsECCGetResultString(validation));
+ free(curve);
+ free(pub);
+ return NULL;
+ }
+ }
+
+ IppsBigNumState *priv_bn = bytearray_to_privkey(env, privkey, curve);
+
+ IppsBigNumState *share = new_bn(keysize);
+
+ native_timing_start();
+ IppStatus err = ippsECCPSharedSecretDH(priv_bn, pub, share, curve);
+ native_timing_stop();
+
+ free(priv_bn);
+ free(pub);
+ free(curve);
+
+ if (err != ippStsNoErr) {
+ throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err));
+ return NULL;
+ }
+
+ jbyteArray result = (*env)->NewByteArray(env, coord_size);
+ jbyte *data = (*env)->GetByteArrayElements(env, result, NULL);
+ bn_get(share, (uint8_t *) data, coord_size);
+ (*env)->ReleaseByteArrayElements(env, result, data, 0);
+ free(share);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Ippcp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Ippcp_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ jint keysize;
+ IppsECCPState *curve = create_curve(env, params, &keysize);
+
+ if (VALIDATE_CURVE) {
+ IppECResult validation;
+ ippsECCPValidate(50, &validation, curve, ippsPRNGen, prng_state);
+ if (validation != ippECValid) {
+ throw_new(env, "java/security/GeneralSecurityException", ippsECCGetResultString(validation));
+ free(curve);
+ return NULL;
+ }
+ }
+ IppsBigNumState *priv_bn = bytearray_to_privkey(env, privkey, curve);
+
+ IppsECCPPointState *ephemeral_point = new_point(keysize);
+ int ord_bits;
+ ippsECCPGetOrderBitSize(&ord_bits, curve);
+ int ord_bytes = (ord_bits + 7) / 8;
+ IppsBigNumState *ephemeral_secret = new_bn(ord_bits);
+ IppsBigNumState *r = new_bn(ord_bits);
+ IppsBigNumState *s = new_bn(ord_bits);
+
+ jint data_size = (*env)->GetArrayLength(env, data);
+ IppsBigNumState *data_bn = new_bn(data_size * 8);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ ippsSetOctString_BN((Ipp8u *) data_data, data_size, data_bn);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ jbyteArray result = NULL;
+ jbyte r_buf[ord_bytes];
+ jbyte s_buf[ord_bytes];
+
+ native_timing_start();
+ IppStatus err = ippsECCPGenKeyPair(ephemeral_secret, ephemeral_point, curve, prng_wrapper, prng_state);
+ if (err != ippStsNoErr) {
+ throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err));
+ goto error;
+ }
+ err = ippsECCPSetKeyPair(ephemeral_secret, ephemeral_point, ippFalse, curve);
+ if (err != ippStsNoErr) {
+ throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err));
+ goto error;
+ }
+ err = ippsECCPSignDSA(data_bn, priv_bn, r, s, curve);
+ if (err != ippStsNoErr) {
+ throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err));
+ goto error;
+ }
+ native_timing_stop();
+
+ bn_get(r, (uint8_t *) r_buf, ord_bytes);
+ bn_get(s, (uint8_t *) s_buf, ord_bytes);
+
+ result = asn1_der_encode(env, r_buf, ord_bytes, s_buf, ord_bytes);
+
+error:
+ free(curve);
+ free(priv_bn);
+ free(ephemeral_point);
+ free(ephemeral_secret);
+ free(r);
+ free(s);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Ippcp_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jint keysize;
+ IppsECCPState *curve = create_curve(env, params, &keysize);
+
+ if (VALIDATE_CURVE) {
+ IppECResult validation;
+ ippsECCPValidate(50, &validation, curve, ippsPRNGen, prng_state);
+ if (validation != ippECValid) {
+ throw_new(env, "java/security/GeneralSecurityException", ippsECCGetResultString(validation));
+ free(curve);
+ return JNI_FALSE;
+ }
+ }
+ IppsECCPPointState *pub = bytearray_to_pubkey(env, pubkey, keysize, curve);
+
+ if (VALIDATE_POINT) {
+ IppECResult validation;
+ ippsECCPCheckPoint(pub, &validation, curve);
+ if (validation != ippECValid) {
+ throw_new(env, "java/security/GeneralSecurityException", ippsECCGetResultString(validation));
+ free(curve);
+ free(pub);
+ return JNI_FALSE;
+ }
+ }
+
+ size_t r_len, s_len;
+ jbyte *r_data, *s_data;
+ bool decode = asn1_der_decode(env, signature, &r_data, &r_len, &s_data, &s_len);
+ if (!decode) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error decoding sig.");
+ free(curve);
+ free(pub);
+ return JNI_FALSE;
+ }
+
+ int ord_bits;
+ ippsECCPGetOrderBitSize(&ord_bits, curve);
+
+ IppsBigNumState *r = new_bn(ord_bits);
+ ippsSetOctString_BN((Ipp8u *) r_data, r_len, r);
+ free(r_data);
+ IppsBigNumState *s = new_bn(ord_bits);
+ ippsSetOctString_BN((Ipp8u *) s_data, s_len, s);
+ free(s_data);
+
+ jint data_size = (*env)->GetArrayLength(env, data);
+ IppsBigNumState *data_bn = new_bn(data_size * 8);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ ippsSetOctString_BN((Ipp8u *) data_data, data_size, data_bn);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ IppECResult result;
+
+ native_timing_start();
+ ippsECCPSetKeyPair(NULL, pub, ippTrue, curve);
+ IppStatus err = ippsECCPVerifyDSA(data_bn, r, s, &result, curve);
+ native_timing_stop();
+
+ free(curve);
+ free(pub);
+ free(r);
+ free(s);
+
+ if (err == ippStsNoErr && result == ippECValid) {
+ return JNI_TRUE;
+ }
+ if (err != ippStsNoErr) {
+ throw_new(env, "java/security/GeneralSecurityException", ippcpGetStatusString(err));
+ return JNI_FALSE;
+ }
+
+ return JNI_FALSE;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/libressl.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/libressl.c
new file mode 100644
index 0000000..79227f8
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/libressl.c
@@ -0,0 +1,609 @@
+#include "native.h"
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/opensslv.h>
+#include <openssl/objects.h>
+#include <openssl/obj_mac.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_LibresslLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Libressl");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, LIBRESSL_VERSION_TEXT);
+ long ver_hi = (LIBRESSL_VERSION_NUMBER & 0xff000000L) >> 28;
+ long ver_mid = (LIBRESSL_VERSION_NUMBER & 0x00ff0000L) >> 20;
+ long ver_low = (LIBRESSL_VERSION_NUMBER & 0x0000ff00L) >> 12;
+ double version = (double)ver_hi + ((double)ver_mid/10) + ((double)ver_low/100);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Libressl_setup(JNIEnv *env, jobject self) {
+ OPENSSL_init_crypto(0, NULL);
+
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, self, "EC", "Libressl");
+ ADD_KA(env, self, "ECDH", "LibresslECDH");
+ ADD_SIG(env, self, "NONEwithECDSA", "LibresslECDSAwithNONE");
+
+ init_classes(env, "Libressl");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_LibresslLib_getCurves(JNIEnv *env, jobject self) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ jstring curve_name = (*env)->NewStringUTF(env, OBJ_nid2sn(curves[i].nid));
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_keysizeSupported(JNIEnv *env, jobject self, jint keysize) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ EC_GROUP *curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ EC_GROUP_free(curve);
+ return JNI_TRUE;
+ }
+ EC_GROUP_free(curve);
+ }
+ return JNI_FALSE;
+}
+
+static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ int size = BN_num_bytes(bn);
+ jbyteArray bytes = (*env)->NewByteArray(env, size);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ BN_bn2bin(bn, (unsigned char *) data);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) {
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
+ jsize byte_length = (*env)->GetArrayLength(env, byte_array);
+ jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL);
+ (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static EC_GROUP *create_curve(JNIEnv *env, jobject params) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+ BIGNUM *a_bn = biginteger_to_bignum(env, a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+ BIGNUM *b_bn = biginteger_to_bignum(env, b);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+ BIGNUM *gx_bn = biginteger_to_bignum(env, gx);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+ BIGNUM *gy_bn = biginteger_to_bignum(env, gy);
+
+ EC_GROUP *result;
+ EC_POINT *g_point;
+
+ if ((*env)->IsInstanceOf(env, field, fp_field_class)) {
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ BIGNUM *p_bn = biginteger_to_bignum(env, p);
+ result = EC_GROUP_new_curve_GFp(p_bn, a_bn, b_bn, NULL);
+ BN_free(p_bn);
+
+ if (!result) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_new_curve_GFp.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn);
+ return NULL;
+ }
+
+ g_point = EC_POINT_new(result);
+ if(!EC_POINT_set_affine_coordinates_GFp(result, g_point, gx_bn, gy_bn, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_POINT_set_affine_coordinates_GFp.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+ } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ jmethodID get_reduction_poly = (*env)->GetMethodID(env, f2m_field_class, "getReductionPolynomial", "()Ljava/math/BigInteger;");
+ jobject red_poly = (*env)->CallObjectMethod(env, field, get_reduction_poly);
+
+ BIGNUM *p_bn = biginteger_to_bignum(env, red_poly);
+ result = EC_GROUP_new_curve_GF2m(p_bn, a_bn, b_bn, NULL);
+ BN_free(p_bn);
+ if (!result) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_new_curve_GF2m.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn);
+ return NULL;
+ }
+
+ g_point = EC_POINT_new(result);
+ if(!EC_POINT_set_affine_coordinates_GF2m(result, g_point, gx_bn, gy_bn, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_POINT_set_affine_coordinates_GF2m.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+
+ BN_free(a_bn);
+ BN_free(b_bn);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ BIGNUM *n_bn = biginteger_to_bignum(env, n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = (*env)->CallIntMethod(env, params, get_h);
+ BIGNUM *h_bn = BN_new();
+ BN_set_word(h_bn, h);
+
+ if (!EC_GROUP_set_generator(result, g_point, n_bn, h_bn)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_set_generator.");
+ BN_free(n_bn); BN_free(h_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+
+ EC_POINT_free(g_point);
+ BN_free(gx_bn);
+ BN_free(gy_bn);
+ BN_free(n_bn);
+ BN_free(h_bn);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jboolean result = (EC_GROUP_check(curve, NULL) == 1) ? JNI_TRUE : JNI_FALSE;
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
+ int field_type = EC_METHOD_get_field_type(EC_GROUP_method_of(curve));
+ BIGNUM *a;
+ BIGNUM *b;
+
+ BIGNUM *gx;
+ BIGNUM *gy;
+ jobject field;
+
+ a = BN_new();
+ b = BN_new();
+
+ if (field_type == NID_X9_62_prime_field) {
+ BIGNUM *p = BN_new();
+
+ if (!EC_GROUP_get_curve_GFp(curve, p, a, b, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_curve_GFp.");
+ BN_free(p); BN_free(a); BN_free(b);
+ return NULL;
+ }
+
+ jobject p_int = bignum_to_biginteger(env, p);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int);
+
+ BN_free(p);
+
+ gx = BN_new();
+ gy = BN_new();
+ if (!EC_POINT_get_affine_coordinates_GFp(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_POINT_get_affine_coordinates_GFp.");
+ BN_free(a); BN_free(b); BN_free(gx); BN_free(gy);
+ return NULL;
+ }
+ } else if (field_type == NID_X9_62_characteristic_two_field) {
+ if (!EC_GROUP_get_curve_GF2m(curve, NULL, a, b, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_curve_GF2m.");
+ BN_free(a); BN_free(b);
+ return NULL;
+ }
+
+ int basis_type = EC_GROUP_get_basis_type(curve);
+ jintArray ks;
+ jint *ks_data;
+ if (basis_type == NID_X9_62_tpBasis) {
+ ks = (*env)->NewIntArray(env, 1);
+ ks_data = (*env)->GetIntArrayElements(env, ks, NULL);
+ if (!EC_GROUP_get_trinomial_basis(curve, (unsigned int *) &ks_data[0])) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_trinomial_basis.");
+ BN_free(a); BN_free(b);
+ (*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT);
+ return NULL;
+ }
+ } else if (basis_type == NID_X9_62_ppBasis) {
+ ks = (*env)->NewIntArray(env, 3);
+ ks_data = (*env)->GetIntArrayElements(env, ks, NULL);
+ if (!EC_GROUP_get_pentanomial_basis(curve, (unsigned int *) &ks_data[0], (unsigned int *) &ks_data[1], (unsigned int *) &ks_data[2])) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_pentanomial_basis.");
+ BN_free(a); BN_free(b);
+ (*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT);
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ (*env)->ReleaseIntArrayElements(env, ks, ks_data, 0);
+
+ jint m = EC_GROUP_get_degree(curve);
+
+ jmethodID f2m_field_init = (*env)->GetMethodID(env, f2m_field_class, "<init>", "(I[I)V");
+ field = (*env)->NewObject(env, f2m_field_class, f2m_field_init, m, ks);
+
+ gx = BN_new();
+ gy = BN_new();
+ if (!EC_POINT_get_affine_coordinates_GF2m(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_POINT_get_affine_coordinates_GF2m.");
+ BN_free(a); BN_free(b); BN_free(gx); BN_free(gy);
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+
+ jobject a_int = bignum_to_biginteger(env, a);
+ jobject b_int = bignum_to_biginteger(env, b);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int);
+
+ BN_free(a);
+ BN_free(b);
+
+ jobject gx_int = bignum_to_biginteger(env, gx);
+ jobject gy_int = bignum_to_biginteger(env, gy);
+
+ BN_free(gx);
+ BN_free(gy);
+
+ BN_CTX *ctx = BN_CTX_new();
+ if (!ctx) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException",
+ "Could not create bignum context.");
+ return NULL;
+ }
+
+ BN_CTX_start(ctx);
+
+ BIGNUM *order = BN_CTX_get(ctx);
+ if (!order || !EC_GROUP_get_order(curve, order, ctx)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException",
+ "Could not obtain curve order.");
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return NULL;
+ }
+
+ jobject order_obj = bignum_to_biginteger(env, order);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+
+ BIGNUM *h = BN_new();
+ EC_GROUP_get_cofactor(curve, h, NULL);
+ jint cofactor = BN_get_word(h);
+ BN_free(h);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order_obj, cofactor);
+}
+
+static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
+ jint keysize = EC_GROUP_get_degree(curve);
+ unsigned long key_bytes = (keysize + 7) / 8;
+
+ EC_KEY *key = EC_KEY_new();
+ EC_KEY_set_group(key, curve);
+
+ native_timing_start();
+ int err = EC_KEY_generate_key(key);
+ native_timing_stop();
+
+ if (!err) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key.");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ int priv_len = BN_num_bytes(EC_KEY_get0_private_key(key));
+ memset(key_priv, 0, key_bytes);
+ BN_bn2bin(EC_KEY_get0_private_key(key), (unsigned char *) key_priv + (key_bytes - priv_len));
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ unsigned long key_len = 2*key_bytes + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, (unsigned char *) key_pub, key_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ EC_KEY_free(key);
+
+ jobject ec_param_spec = create_ec_param_spec(env, curve);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ break;
+ }
+ EC_GROUP_free(curve);
+ }
+
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize pub_len = (*env)->GetArrayLength(env, pub);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
+ EC_POINT *pub_point = EC_POINT_new(curve);
+ EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT);
+ EC_KEY_set_public_key(result, pub_point);
+ EC_POINT_free(pub_point);
+ return result;
+}
+
+EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize priv_len = (*env)->GetArrayLength(env, priv);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
+ BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT);
+ EC_KEY_set_private_key(result, s);
+ BN_free(s);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Libressl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ int field_size = EC_GROUP_get_degree(curve);
+ size_t secret_len = (field_size + 7)/8;
+
+ //TODO: Do more KeyAgreements here, but will have to do the hash-fun manually,
+ // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string.
+ jbyteArray result = (*env)->NewByteArray(env, secret_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+
+ native_timing_start();
+ int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL);
+ native_timing_stop();
+
+ if (err <= 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key.");
+ EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ EC_KEY_free(pub);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Libressl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Libressl_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually?
+
+ native_timing_start();
+ ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv);
+ native_timing_stop();
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ if (!signature) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign.");
+ EC_KEY_free(priv); EC_GROUP_free(curve);
+ return NULL;
+ }
+
+ jsize sig_len = i2d_ECDSA_SIG(signature, NULL);
+ jbyteArray result = (*env)->NewByteArray(env, sig_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ jbyte *result_data_ptr = result_data;
+ i2d_ECDSA_SIG(signature, (unsigned char **)&result_data_ptr);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ ECDSA_SIG_free(signature);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Libressl_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return JNI_FALSE;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+
+ jsize sig_len = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+ jbyte *sig_data_ptr = sig_data;
+ ECDSA_SIG *sig_obj = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig_data_ptr, sig_len);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub);
+ native_timing_stop();
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ if (result < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify.");
+ EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj);
+ return JNI_FALSE;
+ }
+
+ ECDSA_SIG_free(sig_obj);
+ EC_KEY_free(pub);
+ EC_GROUP_free(curve);
+ return (result == 1) ? JNI_TRUE : JNI_FALSE;
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/matrixssl.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/matrixssl.c
new file mode 100644
index 0000000..8324dd4
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/matrixssl.c
@@ -0,0 +1,397 @@
+#include "native.h"
+#include <string.h>
+#include <stdio.h>
+
+#include <cryptoApi.h>
+#include <coreApi.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+static jclass provider_class;
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MatrixsslLib_createProvider(JNIEnv *env, jobject this) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Matrixssl");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, "MatrixSSL");
+ double version = 4.1;
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Matrixssl_setup(JNIEnv *env, jobject this) {
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, this, "EC", "Matrixssl");
+ ADD_KA(env, this, "ECDH", "MatrixsslECDH");
+ ADD_SIG(env, this, "NONEwithECDSA", "MatrixsslECDSAwithNONE");
+
+ psCoreOpen(PSCORE_CONFIG);
+ psOpenPrng();
+
+ init_classes(env, "Matrixssl");
+}
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MatrixsslLib_getCurves(JNIEnv *env, jobject this) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+ size_t i = 0;
+ while (eccCurves[i].size > 0) {
+ jstring curve_name = (*env)->NewStringUTF(env, eccCurves[i].name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ i++;
+ }
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_keysizeSupported(JNIEnv *env, jobject this, jint keysize) {
+ size_t i = 0;
+ while (eccCurves[i].size > 0) {
+ if (eccCurves[i].size * 8 == keysize) {
+ return JNI_TRUE;
+ }
+ i++;
+ }
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_paramsSupported(JNIEnv *env, jobject this, jobject params) {
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+ if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t i = 0;
+ while (eccCurves[i].size > 0) {
+ if (strcasecmp(utf_name, eccCurves[i].name) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ i++;
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+
+static jobject create_ec_param_spec(JNIEnv *env, const psEccCurve_t *curve) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(Ljava/lang/String;I)V");
+
+ jstring p_string = (*env)->NewStringUTF(env, curve->prime);
+ jobject p = (*env)->NewObject(env, biginteger_class, biginteger_init, p_string, (jint) 16);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p);
+
+ jstring a_string = (*env)->NewStringUTF(env, curve->A);
+ jobject a = (*env)->NewObject(env, biginteger_class, biginteger_init, a_string, (jint) 16);
+ jstring b_string = (*env)->NewStringUTF(env, curve->B);
+ jobject b = (*env)->NewObject(env, biginteger_class, biginteger_init, b_string, (jint) 16);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a, b);
+
+ jstring gx_string = (*env)->NewStringUTF(env, curve->Gx);
+ jstring gy_string = (*env)->NewStringUTF(env, curve->Gy);
+ jobject gx = (*env)->NewObject(env, biginteger_class, biginteger_init, gx_string, (jint) 16);
+ jobject gy = (*env)->NewObject(env, biginteger_class, biginteger_init, gy_string, (jint) 16);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy);
+
+ jstring n_string = (*env)->NewStringUTF(env, curve->order);
+ jobject n = (*env)->NewObject(env, biginteger_class, biginteger_init, n_string, (jint) 16);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, (jint) 1);
+}
+
+static psEccCurve_t *create_curve(JNIEnv *env, jobject params) {
+ psEccCurve_t *curve = calloc(sizeof(psEccCurve_t), 1);
+
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ jint bytes = (bits + 7) / 8;
+ curve->size = bytes;
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+
+ //jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ //jint h = (*env)->CallIntMethod(env, params, get_h);
+
+ jmethodID get_bitlength = (*env)->GetMethodID(env, biginteger_class, "bitLength", "()I");
+ jint ord_bits = (*env)->CallIntMethod(env, n, get_bitlength);
+ jint ord_bytes = (ord_bits + 7) / 8;
+
+ curve->prime = biginteger_to_hex(env, p, bytes);
+ curve->A = biginteger_to_hex(env, a, bytes);
+ curve->B = biginteger_to_hex(env, b, bytes);
+ curve->Gx = biginteger_to_hex(env, gx, bytes);
+ curve->Gy = biginteger_to_hex(env, gy, bytes);
+ curve->order = biginteger_to_hex(env, n, ord_bytes);
+ return curve;
+}
+
+static void free_curve(psEccCurve_t *curve) {
+ free((char *)curve->prime);
+ free((char *)curve->A);
+ free((char *)curve->B);
+ free((char *)curve->order);
+ free((char *)curve->Gx);
+ free((char *)curve->Gy);
+}
+
+static jobject generate_from_curve(JNIEnv *env, const psEccCurve_t *curve) {
+ psEccKey_t *key;
+ int32_t err = psEccNewKey(NULL, &key, curve);
+ err = psEccInitKey(NULL, key, curve);
+
+ native_timing_start();
+ err = psEccGenKey(NULL, key, curve, NULL);
+ native_timing_stop();
+
+ if (err < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Couldn't generate key.");
+ psEccClearKey(key);
+ psEccDeleteKey(&key);
+ return NULL;
+ }
+
+ jbyteArray priv = (*env)->NewByteArray(env, pstm_unsigned_bin_size(&key->k));
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
+ pstm_to_unsigned_bin(NULL, &key->k, (unsigned char *) priv_data);
+ (*env)->ReleaseByteArrayElements(env, priv, priv_data, 0);
+
+ jint xlen = pstm_unsigned_bin_size(&key->pubkey.x);
+ jint ylen = pstm_unsigned_bin_size(&key->pubkey.y);
+ jbyteArray pub = (*env)->NewByteArray(env, 1 + xlen + ylen);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
+ pub_data[0] = 0x04;
+ pstm_to_unsigned_bin(NULL, &key->pubkey.x, (unsigned char *) (pub_data + 1));
+ pstm_to_unsigned_bin(NULL, &key->pubkey.y, (unsigned char *) (pub_data + 1 + xlen));
+ (*env)->ReleaseByteArrayElements(env, pub, pub_data, 0);
+
+ jobject ec_param_spec = create_ec_param_spec(env, curve);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ psEccDeleteKey(&key);
+
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random) {
+ size_t i = 0;
+ while (eccCurves[i].size > 0) {
+ if (eccCurves[i].size * 8 == keysize) {
+ return generate_from_curve(env, &eccCurves[i]);
+ }
+ i++;
+ }
+ return NULL;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ psEccCurve_t *curve = create_curve(env, params);
+ jobject result = generate_from_curve(env, curve);
+ free_curve(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t i = 0;
+ while (eccCurves[i].size > 0) {
+ if (strcasecmp(utf_name, eccCurves[i].name) == 0) {
+ break;
+ }
+ i++;
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return generate_from_curve(env, &eccCurves[i]);
+ } else {
+ return NULL;
+ }
+}
+
+static psEccKey_t *bytearray_to_privkey(JNIEnv *env, jbyteArray privkey, const psEccCurve_t *curve) {
+ psEccKey_t *result;
+ psEccNewKey(NULL, &result, curve);
+ psEccInitKey(NULL, result, curve);
+
+ pstm_init_for_read_unsigned_bin(NULL, &result->k, curve->size);
+ jint len = (*env)->GetArrayLength(env, privkey);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL);
+ pstm_read_unsigned_bin(&result->k, (unsigned char *) priv_data, len);
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ result->type = PS_PRIVKEY;
+
+ return result;
+}
+
+static psEccKey_t *bytearray_to_pubkey(JNIEnv *env, jbyteArray pubkey, const psEccCurve_t *curve) {
+ psEccKey_t *result;
+ psEccNewKey(NULL, &result, curve);
+ psEccInitKey(NULL, result, curve);
+
+ pstm_init_for_read_unsigned_bin(NULL, &result->pubkey.x, curve->size);
+ pstm_init_for_read_unsigned_bin(NULL, &result->pubkey.y, curve->size);
+ pstm_init_for_read_unsigned_bin(NULL, &result->pubkey.z, curve->size);
+ jbyte *pubkey_data = (*env)->GetByteArrayElements(env, pubkey, NULL);
+ pstm_read_unsigned_bin(&result->pubkey.x, (unsigned char *) (pubkey_data + 1), curve->size);
+ pstm_read_unsigned_bin(&result->pubkey.y, (unsigned char *) (pubkey_data + 1 + curve->size), curve->size);
+ (*env)->ReleaseByteArrayElements(env, pubkey, pubkey_data, JNI_ABORT);
+ pstm_set(&result->pubkey.z, 1);
+ result->type = PS_PUBKEY;
+
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Matrixssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ psEccCurve_t *curve = create_curve(env, params);
+
+ psEccKey_t *priv = bytearray_to_privkey(env, privkey, curve);
+ psEccKey_t *pub = bytearray_to_pubkey(env, pubkey, curve);
+
+ jbyteArray result = (*env)->NewByteArray(env, curve->size);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ psSize_t outlen = curve->size;
+
+ native_timing_start();
+ int32_t err = psEccGenSharedSecret(NULL, priv, pub, (unsigned char *) result_data, &outlen, NULL);
+ native_timing_stop();
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ psEccDeleteKey(&priv);
+ psEccDeleteKey(&pub);
+ free_curve(curve);
+
+ if (err < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Couldn't derive secret.");
+ return NULL;
+ }
+
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Matrixssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Matrixssl_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ psEccCurve_t *curve = create_curve(env, params);
+
+ psEccKey_t *priv = bytearray_to_privkey(env, privkey, curve);
+
+ psSize_t siglen = 512;
+ uint8_t sig[siglen];
+
+ jint data_len = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ native_timing_start();
+ int32_t err = psEccDsaSign(NULL, priv, (unsigned char *) data_data, data_len, sig, &siglen, 0, NULL);
+ native_timing_stop();
+
+ psEccDeleteKey(&priv);
+ free_curve(curve);
+
+ if (err < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Couldn't sign data.");
+ return NULL;
+ }
+
+ jbyteArray result = (*env)->NewByteArray(env, siglen);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ memcpy(result_data, sig, siglen);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Matrixssl_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ psEccCurve_t *curve = create_curve(env, params);
+ psEccKey_t *pub = bytearray_to_pubkey(env, pubkey, curve);
+
+ jint data_len = (*env)->GetArrayLength(env, data);
+ jint sig_len = (*env)->GetArrayLength(env, signature);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+
+ int32_t result;
+ native_timing_start();
+ int32_t err = psEccDsaVerify(NULL, pub, (unsigned char *) data_data, data_len, (unsigned char *) sig_data, sig_len, &result, NULL);
+ native_timing_stop();
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+
+ free_curve(curve);
+ psEccDeleteKey(&pub);
+
+ if (err < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Couldn't verify signature.");
+ return JNI_FALSE;
+ }
+
+ return result < 0 ? JNI_FALSE : JNI_TRUE;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mbedtls.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mbedtls.c
new file mode 100644
index 0000000..2cff6ff
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mbedtls.c
@@ -0,0 +1,544 @@
+#include "native.h"
+#include <string.h>
+
+#include <mbedtls/ecdsa.h>
+#include <mbedtls/ecdh.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/version.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <stdio.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+static mbedtls_ctr_drbg_context ctr_drbg;
+static mbedtls_entropy_context entropy;
+static jclass provider_class;
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MbedTLSLib_createProvider(JNIEnv *env, jobject this) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$MbedTLS");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, MBEDTLS_VERSION_STRING_FULL);
+ double version = MBEDTLS_VERSION_MAJOR + (MBEDTLS_VERSION_MINOR/10) + (MBEDTLS_VERSION_PATCH/100);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+static int dev_urandom(void *data, unsigned char *output, size_t len, size_t *olen) {
+ FILE *file;
+ size_t ret, left = len;
+ unsigned char *p = output;
+ ((void) data);
+
+ *olen = 0;
+
+ file = fopen( "/dev/urandom", "rb" );
+ if (file == NULL) {
+ return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+ }
+
+ while (left > 0) {
+ ret = fread(p, 1, left, file);
+ if (ret == 0 && ferror(file)) {
+ fclose(file);
+ return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+ }
+
+ p += ret;
+ left -= ret;
+ }
+ fclose(file);
+ *olen = len;
+
+ return 0;
+}
+
+static int ctr_drbg_wrapper(void *ctx, unsigned char *buf, size_t len) {
+ native_timing_pause();
+ int result = mbedtls_ctr_drbg_random(ctx, buf, len);
+ native_timing_restart();
+ return result;
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024MbedTLS_setup(JNIEnv *env, jobject this) {
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, this, "EC", "MbedTLS");
+ ADD_KA(env, this, "ECDH", "MbedTLSECDH");
+ ADD_SIG(env, this, "NONEwithECDSA", "MbedTLSECDSAwithNONE");
+
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ mbedtls_entropy_init(&entropy);
+ mbedtls_entropy_add_source(&entropy, dev_urandom, NULL, 32, MBEDTLS_ENTROPY_SOURCE_STRONG);
+ mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+
+ init_classes(env, "MbedTLS");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MbedTLSLib_getCurves(JNIEnv *env, jobject this) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+ for (const mbedtls_ecp_curve_info *curve_info = mbedtls_ecp_curve_list();
+ curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
+ curve_info++) {
+
+ jstring curve_name = (*env)->NewStringUTF(env, curve_info->name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_keysizeSupported(JNIEnv *env, jobject this, jint keysize) {
+ for (const mbedtls_ecp_curve_info *curve_info = mbedtls_ecp_curve_list();
+ curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
+ curve_info++) {
+ if (keysize == curve_info->bit_size) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_paramsSupported(JNIEnv *env, jobject this, jobject params) {
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+ if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ for (const mbedtls_ecp_curve_info *curve_info = mbedtls_ecp_curve_list();
+ curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
+ curve_info++) {
+ if (strcasecmp(utf_name, curve_info->name) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+const char *err_to_string(int error) {
+ switch (error) {
+ case MBEDTLS_ERR_ECP_BAD_INPUT_DATA:
+ return "Bad input parameters to function.";
+ case MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL:
+ return "The buffer is too small to write to.";
+ case MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE:
+ return "The requested feature is not available, for example, the requested curve is not supported.";
+ case MBEDTLS_ERR_ECP_VERIFY_FAILED:
+ return "The signature is not valid.";
+ case MBEDTLS_ERR_ECP_ALLOC_FAILED:
+ return "Memory allocation failed.";
+ case MBEDTLS_ERR_ECP_RANDOM_FAILED:
+ return "Generation of random value, such as ephemeral key, failed.";
+ case MBEDTLS_ERR_ECP_INVALID_KEY:
+ return "Invalid private or public key.";
+ case MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH:
+ return "The buffer contains a valid signature followed by more data.";
+ case MBEDTLS_ERR_MPI_FILE_IO_ERROR:
+ return "An error occurred while reading from or writing to a file.";
+ case MBEDTLS_ERR_MPI_BAD_INPUT_DATA:
+ return "Bad input parameters to function.";
+ case MBEDTLS_ERR_MPI_INVALID_CHARACTER:
+ return "There is an invalid character in the digit string.";
+ case MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL:
+ return "The buffer is too small to write to.";
+ case MBEDTLS_ERR_MPI_NEGATIVE_VALUE:
+ return "The input arguments are negative or result in illegal output.";
+ case MBEDTLS_ERR_MPI_DIVISION_BY_ZERO:
+ return "The input argument for division is zero, which is not allowed.";
+ case MBEDTLS_ERR_MPI_NOT_ACCEPTABLE:
+ return "The input arguments are not acceptable.";
+ case MBEDTLS_ERR_MPI_ALLOC_FAILED:
+ return "Memory allocation failed.";
+ default:
+ return "UNKNOWN.";
+ }
+}
+
+static jobject biginteger_from_mpi(JNIEnv *env, const mbedtls_mpi *mpi) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ size_t size = mbedtls_mpi_size(mpi);
+ jbyteArray bytes = (*env)->NewByteArray(env, size);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ mbedtls_mpi_write_binary(mpi, (unsigned char *) data, size);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static void mpi_from_biginteger(JNIEnv* env, jobject biginteger, mbedtls_mpi *mpi) {
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, biginteger, to_byte_array);
+ jsize byte_length = (*env)->GetArrayLength(env, byte_array);
+ jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ mbedtls_mpi_read_binary(mpi, (unsigned char *) byte_data, byte_length);
+ (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const mbedtls_ecp_group *group) {
+ jobject p = biginteger_from_mpi(env, &group->P);
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p);
+
+ jobject a;
+ if (group->A.p == NULL) {
+ jmethodID biginteger_subtract = (*env)->GetMethodID(env, biginteger_class, "subtract", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;");
+ jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;");
+ jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong) 3);
+ a = (*env)->CallObjectMethod(env, p, biginteger_subtract, three);
+ } else {
+ a = biginteger_from_mpi(env, &group->A);
+ }
+ jobject b = biginteger_from_mpi(env, &group->B);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a, b);
+
+ jobject gx = biginteger_from_mpi(env, &group->G.X);
+ jobject gy = biginteger_from_mpi(env, &group->G.Y);
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy);
+
+ jobject n = biginteger_from_mpi(env, &group->N);
+ jint h = 1;
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, h);
+}
+
+static void create_curve(JNIEnv *env, jobject params, mbedtls_ecp_group *group) {
+ mbedtls_ecp_group_init(group);
+ group->id = 0;
+
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+ mpi_from_biginteger(env, p, &group->P);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, curve, get_a);
+ mpi_from_biginteger(env, a, &group->A);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, curve, get_b);
+ mpi_from_biginteger(env, b, &group->B);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+ mpi_from_biginteger(env, gx, &group->G.X);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+ mpi_from_biginteger(env, gy, &group->G.Y);
+
+ mbedtls_mpi_lset(&group->G.Z, 1);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ mpi_from_biginteger(env, n, &group->N);
+ group->pbits = group->nbits = mbedtls_mpi_bitlen(&group->P);
+ group->h = 0;
+}
+
+static jobject generate_from_curve(JNIEnv *env, mbedtls_ecp_group *group) {
+ mbedtls_mpi d;
+ mbedtls_mpi_init(&d);
+
+ mbedtls_ecp_point Q;
+ mbedtls_ecp_point_init(&Q);
+
+ if (ctr_drbg.reseed_counter >= ctr_drbg.reseed_interval) {
+ // Reseed manually, outside of the timing window, to not disturb the timing data.
+ // They are somewhat disturbed anyway, but we cannot really get rid of that easily.
+ // We also help it by using a wrapper and pausing for random gen.
+ mbedtls_ctr_drbg_reseed(&ctr_drbg, NULL, 0);
+ }
+
+ native_timing_start();
+ int error = mbedtls_ecp_gen_keypair(group, &d, &Q, ctr_drbg_wrapper, &ctr_drbg);
+ native_timing_stop();
+
+ if (error) {
+ throw_new(env, "java/security/GeneralSecurityException", err_to_string(error));
+ mbedtls_mpi_free(&d);
+ mbedtls_ecp_point_free(&Q);
+ return NULL;
+ }
+
+ jint keysize = (jint) mbedtls_mpi_bitlen(&group->N);
+ unsigned long key_bytes = (keysize + 7) / 8;
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ mbedtls_mpi_write_binary(&d, (unsigned char *) key_priv, key_bytes);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ unsigned long key_len = 2*key_bytes + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ size_t out_key_len = 0;
+ mbedtls_ecp_point_write_binary(group, &Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &out_key_len, (unsigned char *) key_pub, key_len);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ jobject ec_param_spec = create_ec_param_spec(env, group);
+
+ mbedtls_mpi_free(&d);
+ mbedtls_ecp_point_free(&Q);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+static jobject generate_from_curve_info(JNIEnv *env, const mbedtls_ecp_curve_info *curve) {
+ mbedtls_ecp_group group;
+ mbedtls_ecp_group_init(&group);
+ mbedtls_ecp_group_load(&group, curve->grp_id);
+ jobject result = generate_from_curve(env, &group);
+ mbedtls_ecp_group_free(&group);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random) {
+ const mbedtls_ecp_curve_info *curve = NULL;
+ for (const mbedtls_ecp_curve_info *curve_info = mbedtls_ecp_curve_list();
+ curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
+ curve_info++) {
+ if (keysize == curve_info->bit_size) {
+ curve = curve_info;
+ break;
+ }
+ }
+
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ return generate_from_curve_info(env, curve);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ mbedtls_ecp_group curve;
+ create_curve(env, params, &curve);
+ jobject result = generate_from_curve(env, &curve);
+ mbedtls_ecp_group_free(&curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const mbedtls_ecp_curve_info *curve = NULL;
+ for (const mbedtls_ecp_curve_info *curve_info = mbedtls_ecp_curve_list();
+ curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
+ curve_info++) {
+ if (strcasecmp(utf_name, curve_info->name) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ curve = curve_info;
+ break;
+ }
+ }
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return NULL;
+ }
+ return generate_from_curve_info(env, curve);
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+static void create_pubkey(JNIEnv *env, jbyteArray pubkey, mbedtls_ecp_group *curve, mbedtls_ecp_point *pub) {
+ mbedtls_ecp_point_init(pub);
+ jsize pub_size = (*env)->GetArrayLength(env, pubkey);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pubkey, NULL);
+ mbedtls_ecp_point_read_binary(curve, pub, (unsigned char *) key_pub, pub_size);
+ (*env)->ReleaseByteArrayElements(env, pubkey, key_pub, JNI_ABORT);
+}
+
+static void create_privkey(JNIEnv *env, jbyteArray privkey, mbedtls_mpi *priv) {
+ mbedtls_mpi_init(priv);
+ jsize priv_size = (*env)->GetArrayLength(env, privkey);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, privkey, NULL);
+ mbedtls_mpi_read_binary(priv, (unsigned char *) key_priv, priv_size);
+ (*env)->ReleaseByteArrayElements(env, privkey, key_priv, JNI_ABORT);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024MbedTLS_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ mbedtls_ecp_group curve;
+ create_curve(env, params, &curve);
+
+ mbedtls_ecp_point pub;
+ create_pubkey(env, pubkey, &curve, &pub);
+
+ mbedtls_mpi priv;
+ create_privkey(env, privkey, &priv);
+
+ mbedtls_mpi result;
+ mbedtls_mpi_init(&result);
+
+ native_timing_start();
+ int error = mbedtls_ecdh_compute_shared(&curve, &result, &pub, &priv, ctr_drbg_wrapper, &ctr_drbg);
+ native_timing_stop();
+
+ if (error) {
+ throw_new(env, "java/security/GeneralSecurityException", err_to_string(error));
+ mbedtls_mpi_free(&result);
+ mbedtls_mpi_free(&priv);
+ mbedtls_ecp_point_free(&pub);
+ mbedtls_ecp_group_free(&curve);
+ return NULL;
+ }
+
+ jint keysize = (jint) mbedtls_mpi_bitlen(&curve.N);
+ unsigned long key_bytes = (keysize + 7) / 8;
+ jbyteArray result_bytes = (*env)->NewByteArray(env, key_bytes);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result_bytes, NULL);
+ mbedtls_mpi_write_binary(&result, (unsigned char *) result_data, key_bytes);
+ (*env)->ReleaseByteArrayElements(env, result_bytes, result_data, 0);
+
+ mbedtls_mpi_free(&result);
+ mbedtls_mpi_free(&priv);
+ mbedtls_ecp_point_free(&pub);
+ mbedtls_ecp_group_free(&curve);
+
+ return result_bytes;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024MbedTLS_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algo) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024MbedTLS_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ mbedtls_ecp_group curve;
+ create_curve(env, params, &curve);
+
+ mbedtls_mpi priv;
+ create_privkey(env, privkey, &priv);
+
+ mbedtls_mpi r;
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi s;
+ mbedtls_mpi_init(&s);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int error = mbedtls_ecdsa_sign(&curve, &r, &s, &priv, (unsigned char *) data_data, data_size, ctr_drbg_wrapper, &ctr_drbg);
+ native_timing_stop();
+
+ mbedtls_mpi_free(&priv);
+ mbedtls_ecp_group_free(&curve);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ if (error) {
+ throw_new(env, "java/security/GeneralSecurityException", err_to_string(error));
+ mbedtls_mpi_free(&r);
+ mbedtls_mpi_free(&s);
+ return NULL;
+ }
+
+ jsize rlen = (mbedtls_mpi_bitlen(&r) + 7) / 8;
+ jbyte r_bytes[rlen];
+ mbedtls_mpi_write_binary(&r, (unsigned char *) r_bytes, rlen);
+ jsize slen = (mbedtls_mpi_bitlen(&s) + 7) / 8;
+ jbyte s_bytes[slen];
+ mbedtls_mpi_write_binary(&s, (unsigned char *) s_bytes, slen);
+
+ mbedtls_mpi_free(&r);
+ mbedtls_mpi_free(&s);
+ return asn1_der_encode(env, r_bytes, rlen, s_bytes, slen);
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024MbedTLS_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ mbedtls_ecp_group curve;
+ create_curve(env, params, &curve);
+
+ mbedtls_ecp_point pub;
+ create_pubkey(env, pubkey, &curve, &pub);
+ jbyte *r_bytes;
+ size_t rlen;
+ jbyte *s_bytes;
+ size_t slen;
+ bool decode = asn1_der_decode(env, signature, &r_bytes, &rlen, &s_bytes, &slen);
+ if (!decode) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error decoding sig.");
+ mbedtls_ecp_point_free(&pub);
+ mbedtls_ecp_group_free(&curve);
+ return JNI_FALSE;
+ }
+
+ mbedtls_mpi r;
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi_read_binary(&r, (unsigned char *) r_bytes, rlen);
+ mbedtls_mpi s;
+ mbedtls_mpi_init(&s);
+ mbedtls_mpi_read_binary(&s, (unsigned char *) s_bytes, slen);
+ free(r_bytes);
+ free(s_bytes);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int error = mbedtls_ecdsa_verify(&curve, (unsigned char *) data_data, data_size, &pub, &r, &s);
+ native_timing_stop();
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ if (error) {
+ if (error != MBEDTLS_ERR_ECP_VERIFY_FAILED) {
+ throw_new(env, "java/security/GeneralSecurityException", err_to_string(error));
+ }
+ mbedtls_ecp_point_free(&pub);
+ mbedtls_ecp_group_free(&curve);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mscng.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mscng.c
new file mode 100644
index 0000000..bb27887
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/mscng.c
@@ -0,0 +1,1273 @@
+#include <windows.h>
+#include <bcrypt.h>
+#include "native.h"
+
+#include "c_timing.h"
+#include "c_utils.h"
+
+// BCRYPT and NT things.
+#define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0)
+#define NT_FAILURE(status) !NT_SUCCESS(status)
+
+#define STATUS_SUCCESS 0x00000000
+#define STATUS_INVALID_SIGNATURE 0xC000A000
+
+typedef struct {
+ ULONG dwVersion; // Version of the structure
+ ECC_CURVE_TYPE_ENUM dwCurveType; // Supported curve types.
+ ECC_CURVE_ALG_ID_ENUM dwCurveGenerationAlgId; // For X.592 verification purposes, if we include Seed we will need to include the algorithm ID.
+ ULONG cbFieldLength; // Byte length of the fields P, A, B, X, Y.
+ ULONG cbSubgroupOrder; // Byte length of the subgroup.
+ ULONG cbCofactor; // Byte length of cofactor of G in E.
+ ULONG cbSeed; // Byte length of the seed used to generate the curve.
+} BCRYPT_ECC_PARAMETER_HEADER;
+
+// Provider things
+static jclass provider_class;
+
+#define KEYFLAG_IMPLICIT 0 // Mscng native key, over named curve
+#define KEYFLAG_EXPLICIT 1 // Mscng native key, over explicit ecc parameters
+#define KEYFLAG_NIST 2 // Mscng native key, over NIST parameters, custom ECDH/ECDSA_P* algo
+#define KEYFLAG_OTHER 3 // Other key, explicit ecc parameters
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider(JNIEnv *env, jobject self) {
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Mscng");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, "Microsoft CNG");
+ double version = 1.0;
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Mscng_setup(JNIEnv *env, jobject self) {
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, self, "ECDH", "MscngECDH");
+ ADD_KPG(env, self, "ECDSA", "MscngECDSA");
+
+ ADD_KA(env, self, "ECDHwithSHA1KDF(CNG)", "MscngECDHwithSHA1KDF");
+ ADD_KA(env, self, "ECDHwithSHA256KDF(CNG)", "MscngECDHwithSHA256KDF");
+ ADD_KA(env, self, "ECDHwithSHA384KDF(CNG)", "MscngECDHwithSHA384KDF");
+ ADD_KA(env, self, "ECDHwithSHA512KDF(CNG)", "MscngECDHwithSHA512KDF");
+
+ ADD_SIG(env, self, "SHA1withECDSA", "MscngECDSAwithSHA1");
+ ADD_SIG(env, self, "SHA256withECDSA", "MscngECDSAwithSHA256");
+ ADD_SIG(env, self, "SHA384withECDSA", "MscngECDSAwithSHA384");
+ ADD_SIG(env, self, "SHA512withECDSA", "MscngECDSAwithSHA112");
+
+ init_classes(env, "Mscng");
+}
+
+typedef struct {
+ LPCSTR name;
+ ULONG bits;
+} named_curve_t;
+
+static named_curve_t named_curves[] = {
+ {"curve25519", 256}, {"brainpoolP160r1", 160}, {"brainpoolP160t1", 160}, {"brainpoolP192r1", 192}, {"brainpoolP192t1", 192},
+ {"brainpoolP224r1", 224}, {"brainpoolP224t1", 224}, {"brainpoolP256r1", 256}, {"brainpoolP256t1", 256}, {"brainpoolP320r1", 320},
+ {"brainpoolP320t1", 320}, {"brainpoolP384r1", 384}, {"brainpoolP384t1", 384}, {"brainpoolP512r1", 512}, {"brainpoolP512t1", 512},
+ {"ec192wapi", 192}, {"nistP192", 192}, {"nistP224", 224}, {"nistP256", 256}, {"nistP384", 384},
+ {"nistP521", 521}, {"numsP256t1", 256}, {"numsP384t1", 384}, {"numsP512t1", 512}, {"secP160k1", 160},
+ {"secP160r1", 160}, {"secP160r2", 160}, {"secP192k1", 192}, {"secP192r1", 192}, {"secP224k1", 224},
+ {"secP224r1", 224}, {"secP256k1", 256}, {"secP256r1", 256}, {"secP384r1", 384}, {"secP521r1", 521},
+ {"wtls12", 224}, {"wtls7", 160}, {"wtls9", 160}, {"x962P192v1", 192}, {"x962P192v2", 192},
+ {"x962P192v3", 192}, {"x962P239v1", 239}, {"x962P239v2", 239}, {"x962P239v3", 239}, {"x962P256v1", 256}};
+
+static const named_curve_t *lookup_curve(const char *name) {
+ for (size_t i = 0; i < sizeof(named_curves) / sizeof(named_curve_t); ++i) {
+ if (strcmp(name, named_curves[i].name) == 0) {
+ return &named_curves[i];
+ }
+ }
+ return NULL;
+}
+
+static ULONG utf_16to8(NPSTR *out_buf, LPCWSTR in_str) {
+ INT result = WideCharToMultiByte(CP_UTF8, 0, in_str, -1, NULL, 0, NULL, NULL);
+ *out_buf = calloc(result, 1);
+ return WideCharToMultiByte(CP_UTF8, 0, in_str, -1, *out_buf, result, NULL, NULL);
+}
+
+static ULONG utf_8to16(NWPSTR *out_buf, LPCSTR in_str) {
+ INT result = MultiByteToWideChar(CP_UTF8, 0, in_str, -1, NULL, 0);
+ *out_buf = calloc(result * sizeof(WCHAR), 1);
+ return MultiByteToWideChar(CP_UTF8, 0, in_str, -1, *out_buf, result);
+}
+
+/**
+ * Convert Java String to UTF-16 NWPSTR null-terminated.
+ * Returns: Length of NWPSTR in bytes!
+ */
+static ULONG utf_strto16(NWPSTR *out_buf, JNIEnv *env, jobject str) {
+ jsize len = (*env)->GetStringLength(env, str);
+ *out_buf = calloc(len * sizeof(jchar) + 1, 1);
+ const jchar *chars = (*env)->GetStringChars(env, str, NULL);
+ memcpy(*out_buf, chars, len * sizeof(jchar));
+ (*env)->ReleaseStringChars(env, str, chars);
+ return len * sizeof(jchar);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurves(JNIEnv *env, jobject self) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ NTSTATUS status;
+ BCRYPT_ALG_HANDLE handle;
+
+ if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&handle, BCRYPT_ECDH_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
+ return result;
+ }
+
+ ULONG bufSize;
+ if (NT_FAILURE(status = BCryptGetProperty(handle, BCRYPT_ECC_CURVE_NAME_LIST, NULL, 0, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptGetProperty(length only)\n", status);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return result;
+ }
+
+ BCRYPT_ECC_CURVE_NAMES *curves = (BCRYPT_ECC_CURVE_NAMES *)calloc(bufSize, 1);
+ if (NT_FAILURE(status = BCryptGetProperty(handle, BCRYPT_ECC_CURVE_NAME_LIST, (PBYTE)curves, bufSize, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptGetProperty(whole)\n", status);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ free(curves);
+ return result;
+ }
+
+ for (size_t i = 0; i < curves->dwEccCurveNames; ++i) {
+ NPSTR curve_name;
+ ULONG len = utf_16to8(&curve_name, curves->pEccCurveNames[i]);
+ jstring c_name = (*env)->NewStringUTF(env, curve_name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, c_name);
+ free(curve_name);
+ }
+
+ free(curves);
+
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_keysizeSupported(JNIEnv *env,
+ jobject self,
+ jint keysize) {
+ switch (keysize) {
+ case 256:
+ case 384:
+ case 521:
+ return JNI_TRUE;
+ default:
+ return JNI_FALSE;
+ }
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_paramsSupported(JNIEnv *env,
+ jobject self,
+ jobject params) {
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const named_curve_t *curve = lookup_curve(utf_name);
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return curve == NULL ? JNI_FALSE : JNI_TRUE;
+ } else if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+
+ if ((*env)->IsInstanceOf(env, field, fp_field_class)) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject bytes_to_biginteger(JNIEnv *env, PBYTE bytes, int len) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ jbyteArray byte_array = (*env)->NewByteArray(env, len);
+ jbyte *data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ memcpy(data, bytes, len);
+ (*env)->ReleaseByteArrayElements(env, byte_array, data, 0);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, byte_array);
+ return result;
+}
+
+static void biginteger_to_bytes(JNIEnv *env, jobject bigint, PBYTE bytes, ULONG len) {
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray)(*env)->CallObjectMethod(env, bigint, to_byte_array);
+ jsize byte_length = (*env)->GetArrayLength(env, byte_array);
+ jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ memcpy(bytes, &byte_data[byte_length - len], len);
+ (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, PBYTE eccParams, PULONG paramLength) {
+ //
+ // BCRYPT_ECCFULLKEY_BLOB header
+ // P[cbFieldLength] Prime specifying the base field.
+ // A[cbFieldLength] Coefficient A of the equation y^2 = x^3 + A*x + B mod p
+ // B[cbFieldLength] Coefficient B of the equation y^2 = x^3 + A*x + B mod p
+ // Gx[cbFieldLength] X-coordinate of the base point.
+ // Gy[cbFieldLength] Y-coordinate of the base point.
+ // n[cbSubgroupOrder] Order of the group generated by G = (x,y)
+ // h[cbCofactor] Cofactor of G in E.
+ // S[cbSeed] Seed of the curve.
+
+ BCRYPT_ECCFULLKEY_BLOB *header = (BCRYPT_ECCFULLKEY_BLOB *)eccParams;
+ PBYTE paramsStart = &eccParams[sizeof(BCRYPT_ECCFULLKEY_BLOB)];
+
+ // cbFieldLength
+ PBYTE P = paramsStart;
+ PBYTE A = P + header->cbFieldLength;
+ PBYTE B = A + header->cbFieldLength;
+ PBYTE GX = B + header->cbFieldLength;
+ PBYTE GY = GX + header->cbFieldLength;
+
+ // cbSubgroupOrder
+ PBYTE N = GY + header->cbFieldLength;
+
+ // cbCofactor
+ PBYTE H = N + header->cbSubgroupOrder;
+
+ // cbSeed
+ PBYTE S = H + header->cbCofactor;
+
+ *paramLength =
+ sizeof(BCRYPT_ECCFULLKEY_BLOB) + 5 * header->cbFieldLength + header->cbSubgroupOrder + header->cbCofactor + header->cbSeed;
+
+ jobject p_int = bytes_to_biginteger(env, P, header->cbFieldLength);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int);
+
+ jobject a_int = bytes_to_biginteger(env, A, header->cbFieldLength);
+ jobject b_int = bytes_to_biginteger(env, B, header->cbFieldLength);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>",
+ "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int);
+
+ jobject gx_int = bytes_to_biginteger(env, GX, header->cbFieldLength);
+ jobject gy_int = bytes_to_biginteger(env, GY, header->cbFieldLength);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int);
+
+ jobject n_int = bytes_to_biginteger(env, N, header->cbSubgroupOrder);
+
+ jobject h_int = bytes_to_biginteger(env, H, header->cbCofactor);
+ jmethodID bigint_to_int = (*env)->GetMethodID(env, biginteger_class, "intValue", "()I");
+ jint cof = (*env)->CallIntMethod(env, h_int, bigint_to_int);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(
+ env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n_int, cof);
+}
+
+static ULONG create_curve(JNIEnv *env, jobject params, PBYTE *curve) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ jint bytes = (bits + 7) / 8;
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = (*env)->CallIntMethod(env, params, get_h);
+
+ jmethodID get_bitlength = (*env)->GetMethodID(env, biginteger_class, "bitLength", "()I");
+ jint order_bits = (*env)->CallIntMethod(env, n, get_bitlength);
+ jint order_bytes = (order_bits + 7) / 8;
+
+ // header_size + 5*bytes + order_bytes + cof_size + 0
+ ULONG bufSize = sizeof(BCRYPT_ECC_PARAMETER_HEADER) + 5 * bytes + order_bytes + 1 + 0;
+ *curve = calloc(bufSize, 1);
+ BCRYPT_ECC_PARAMETER_HEADER *header = (BCRYPT_ECC_PARAMETER_HEADER *)*curve;
+ header->dwVersion = 1;
+ header->dwCurveType = 1; // 1 -> Prime short Weierstrass, 2 -> Prime Twisted Edwards, 3 -> Montgomery
+ header->dwCurveGenerationAlgId = 0;
+ header->cbFieldLength = bytes;
+ header->cbSubgroupOrder = order_bytes;
+ header->cbCofactor = 1;
+ header->cbSeed = 0;
+
+ PBYTE paramsStart = &(*curve)[sizeof(BCRYPT_ECC_PARAMETER_HEADER)];
+
+ biginteger_to_bytes(env, p, paramsStart, bytes);
+ biginteger_to_bytes(env, a, paramsStart + bytes, bytes);
+ biginteger_to_bytes(env, b, paramsStart + 2 * bytes, bytes);
+ biginteger_to_bytes(env, gx, paramsStart + 3 * bytes, bytes);
+ biginteger_to_bytes(env, gy, paramsStart + 4 * bytes, bytes);
+ biginteger_to_bytes(env, n, paramsStart + 5 * bytes, order_bytes);
+ PBYTE cof_ptr = (PBYTE)(paramsStart + 5 * bytes + order_bytes);
+ *cof_ptr = (BYTE)h;
+ return bufSize;
+}
+
+static ULONG init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, jint *keyflag, NWPSTR *curve_name, LPCWSTR algo, jobject params) {
+ NTSTATUS status;
+ if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(handle, algo, MS_PRIMITIVE_PROVIDER, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
+ return 0;
+ }
+ ULONG result = 0;
+ if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ jint utf_length = (*env)->GetStringUTFLength(env, name);
+ PUCHAR chars = calloc(utf_length + 1, 1);
+ (*env)->GetStringUTFRegion(env, name, 0, utf_length, chars);
+ const named_curve_t *curve = lookup_curve(chars);
+ ULONG ret = utf_8to16(curve_name, chars);
+ if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, (PUCHAR)*curve_name, ret * sizeof(WCHAR), 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status);
+ return 0;
+ }
+ free(chars);
+ result = curve->bits;
+ *keyflag = KEYFLAG_IMPLICIT;
+ } else if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ PBYTE curve;
+ ULONG curveLen = create_curve(env, params, &curve);
+ if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_PARAMETERS, curve, curveLen, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status);
+ return 0;
+ }
+ free(curve);
+
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ result = bits;
+ *keyflag = KEYFLAG_EXPLICIT;
+ *curve_name = NULL;
+ }
+ return result;
+}
+
+static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key, jint flag, LPCWSTR curve) {
+ NTSTATUS status;
+ ULONG bufSize = 0;
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, NULL, 0, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, length only)\n", status);
+ return NULL;
+ }
+ if (bufSize == 0) {
+ printf("buf 0\n");
+ return NULL;
+ }
+
+ PBYTE fullBuf = calloc(bufSize, 1);
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, fullBuf, bufSize, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, whole)\n", status);
+ free(fullBuf);
+ return NULL;
+ }
+
+ ULONG paramLength;
+ jobject ec_priv_param_spec = create_ec_param_spec(env, fullBuf, &paramLength);
+
+ // fullBuf looks like:
+ // BCRYPT_ECCFULLKEY_BLOB header
+ // P[cbFieldLength] Prime specifying the base field.
+ // A[cbFieldLength] Coefficient A of the equation y^2 = x^3 + A*x + B mod p
+ // B[cbFieldLength] Coefficient B of the equation y^2 = x^3 + A*x + B mod p
+ // Gx[cbFieldLength] X-coordinate of the base point.
+ // Gy[cbFieldLength] Y-coordinate of the base point.
+ // n[cbSubgroupOrder] Order of the group generated by G = (x,y)
+ // h[cbCofactor] Cofactor of G in E.
+ // S[cbSeed] Seed of the curve.
+ // Qx[cbFieldLength] X-coordinate of the public point.
+ // Qy[cbFieldLength] Y-coordinate of the public point.
+ // d[cbSubgroupOrder] Private key.
+ BCRYPT_ECCFULLKEY_BLOB *privHeader = (BCRYPT_ECCFULLKEY_BLOB *)fullBuf;
+ PBYTE priv_x = &fullBuf[paramLength];
+ PBYTE priv_y = priv_x + privHeader->cbFieldLength;
+ PBYTE priv = priv_y + privHeader->cbFieldLength;
+
+ jbyteArray meta_bytes = NULL;
+ jbyteArray header_bytes = NULL;
+ switch (flag) {
+ case 0: {
+ // meta = curve
+ jint meta_len = (wcslen(curve) + 1) * sizeof(WCHAR);
+ meta_bytes = (*env)->NewByteArray(env, meta_len);
+ jbyte *meta_data = (*env)->GetByteArrayElements(env, meta_bytes, NULL);
+ memcpy(meta_data, curve, meta_len);
+ (*env)->ReleaseByteArrayElements(env, meta_bytes, meta_data, 0);
+ }
+ case 1:
+ case 2: {
+ // meta = null
+ // header = full
+ header_bytes = (*env)->NewByteArray(env, paramLength);
+ jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL);
+ memcpy(header_data, fullBuf, paramLength);
+ (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0);
+ break;
+ }
+ default:
+ // header = small
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, length only)\n", status);
+ free(fullBuf);
+ return NULL;
+ }
+ if (bufSize == 0) {
+ printf("buf 0\n");
+ free(fullBuf);
+ return NULL;
+ }
+ PBYTE smallBuf = calloc(bufSize, 1);
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, smallBuf, bufSize, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, whole)\n", status);
+ free(fullBuf);
+ free(smallBuf);
+ return NULL;
+ }
+ // smallBuf looks like:
+ // BCRYPT_ECCKEY_BLOB header
+ // Qx[cbFieldLength] X-coordinate of the public point.
+ // Qy[cbFieldLength] Y-coordinate of the public point.
+ // d[cbSubgroupOrder] Private key.
+ header_bytes = (*env)->NewByteArray(env, sizeof(BCRYPT_ECCKEY_BLOB));
+ jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL);
+ memcpy(header_data, smallBuf, sizeof(BCRYPT_ECCKEY_BLOB));
+ (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0);
+ free(smallBuf);
+ break;
+ }
+
+ jbyteArray x_bytes = (*env)->NewByteArray(env, privHeader->cbFieldLength);
+ jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL);
+ memcpy(x_data, priv_x, privHeader->cbFieldLength);
+ (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0);
+
+ jbyteArray y_bytes = (*env)->NewByteArray(env, privHeader->cbFieldLength);
+ jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL);
+ memcpy(y_data, priv_y, privHeader->cbFieldLength);
+ (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0);
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, privHeader->cbSubgroupOrder);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ memcpy(key_priv, priv, privHeader->cbSubgroupOrder);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ free(fullBuf);
+
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "(I[B[B[B[B[BLjava/security/spec/ECParameterSpec;)V");
+ return (*env)->NewObject(env, privkey_class, ec_priv_init, flag, meta_bytes, header_bytes, x_bytes, y_bytes, priv_bytes,
+ ec_priv_param_spec);
+}
+
+static jobject key_to_pubkey(JNIEnv *env, BCRYPT_KEY_HANDLE key, jint flag, LPCWSTR curve) {
+ NTSTATUS status;
+ ULONG bufSize = 0;
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, NULL, 0, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, length only)\n", status);
+ return NULL;
+ }
+ if (bufSize == 0) {
+ printf("err0\n");
+ return NULL;
+ }
+
+ PBYTE fullBuf = calloc(bufSize, 1);
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, fullBuf, bufSize, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, whole)\n", status);
+ return NULL;
+ }
+
+ ULONG paramLength;
+ jobject ec_pub_param_spec = create_ec_param_spec(env, fullBuf, &paramLength);
+
+ // fullBuf looks like:
+ // BCRYPT_ECCFULLKEY_BLOB header
+ // P[cbFieldLength] Prime specifying the base field.
+ // A[cbFieldLength] Coefficient A of the equation y^2 = x^3 + A*x + B mod p
+ // B[cbFieldLength] Coefficient B of the equation y^2 = x^3 + A*x + B mod p
+ // Gx[cbFieldLength] X-coordinate of the base point.
+ // Gy[cbFieldLength] Y-coordinate of the base point.
+ // n[cbSubgroupOrder] Order of the group generated by G = (x,y)
+ // h[cbCofactor] Cofactor of G in E.
+ // S[cbSeed] Seed of the curve.
+ // Qx[cbFieldLength] X-coordinate of the public point.
+ // Qy[cbFieldLength] Y-coordinate of the public point.
+ BCRYPT_ECCFULLKEY_BLOB *pubHeader = (BCRYPT_ECCFULLKEY_BLOB *)fullBuf;
+ PBYTE pub_x = &fullBuf[paramLength];
+ PBYTE pub_y = pub_x + pubHeader->cbFieldLength;
+
+ jbyteArray meta_bytes = NULL;
+ jbyteArray header_bytes = NULL;
+ switch (flag) {
+ case 0: {
+ // meta = curve
+ jint meta_len = (wcslen(curve) + 1) * sizeof(WCHAR);
+ meta_bytes = (*env)->NewByteArray(env, meta_len);
+ jbyte *meta_data = (*env)->GetByteArrayElements(env, meta_bytes, NULL);
+ memcpy(meta_data, curve, meta_len);
+ (*env)->ReleaseByteArrayElements(env, meta_bytes, meta_data, 0);
+ }
+ case 1:
+ case 2: {
+ header_bytes = (*env)->NewByteArray(env, paramLength);
+ jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL);
+ memcpy(header_data, pubHeader, paramLength);
+ (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0);
+ break;
+ }
+ default:
+ // header = small
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, length only)\n", status);
+ free(fullBuf);
+ return NULL;
+ }
+ if (bufSize == 0) {
+ printf("buf 0\n");
+ free(fullBuf);
+ return NULL;
+ }
+ PBYTE smallBuf = calloc(bufSize, 1);
+ if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, smallBuf, bufSize, &bufSize, 0))) {
+ wprintf(L"**** Error 0x%x returned by BCryptExportKey(small, whole)\n", status);
+ free(fullBuf);
+ free(smallBuf);
+ return NULL;
+ }
+ // smallBuf looks like:
+ // BCRYPT_ECCKEY_BLOB header
+ // Qx[cbFieldLength] X-coordinate of the public point.
+ // Qy[cbFieldLength] Y-coordinate of the public point.
+ header_bytes = (*env)->NewByteArray(env, sizeof(BCRYPT_ECCKEY_BLOB));
+ jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL);
+ memcpy(header_data, smallBuf, sizeof(BCRYPT_ECCKEY_BLOB));
+ (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0);
+ free(smallBuf);
+ break;
+ }
+
+ jbyteArray x_bytes = (*env)->NewByteArray(env, pubHeader->cbFieldLength);
+ jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL);
+ memcpy(x_data, pub_x, pubHeader->cbFieldLength);
+ (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0);
+
+ jbyteArray y_bytes = (*env)->NewByteArray(env, pubHeader->cbFieldLength);
+ jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL);
+ memcpy(y_data, pub_y, pubHeader->cbFieldLength);
+ (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0);
+
+ free(fullBuf);
+
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "(I[B[B[B[BLjava/security/spec/ECParameterSpec;)V");
+ return (*env)->NewObject(env, pubkey_class, ec_pub_init, flag, meta_bytes, header_bytes, x_bytes, y_bytes, ec_pub_param_spec);
+}
+
+JNIEXPORT jobject JNICALL
+Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__ILjava_security_SecureRandom_2(JNIEnv *env,
+ jobject self,
+ jint keysize,
+ jobject random) {
+ NTSTATUS status;
+ BCRYPT_ALG_HANDLE handle = NULL;
+
+ jclass mscng_kpg_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Mscng");
+ jfieldID type_id = (*env)->GetFieldID(env, mscng_kpg_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring)(*env)->GetObjectField(env, self, type_id);
+ const char *type_data = (*env)->GetStringUTFChars(env, type, NULL);
+ LPCWSTR algo;
+ if (strcmp(type_data, "ECDH") == 0) {
+ switch (keysize) {
+ case 256:
+ algo = BCRYPT_ECDH_P256_ALGORITHM;
+ break;
+ case 384:
+ algo = BCRYPT_ECDH_P384_ALGORITHM;
+ break;
+ case 521:
+ algo = BCRYPT_ECDH_P521_ALGORITHM;
+ break;
+ default:
+ // unreachable
+ return NULL;
+ }
+ } else if (strcmp(type_data, "ECDSA") == 0) {
+ switch (keysize) {
+ case 256:
+ algo = BCRYPT_ECDSA_P256_ALGORITHM;
+ break;
+ case 384:
+ algo = BCRYPT_ECDSA_P384_ALGORITHM;
+ break;
+ case 521:
+ algo = BCRYPT_ECDSA_P521_ALGORITHM;
+ break;
+ default:
+ // unreachable
+ return NULL;
+ }
+ } else {
+ // unreachable
+ return NULL;
+ }
+ (*env)->ReleaseStringUTFChars(env, type, type_data);
+
+ if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&handle, algo, MS_PRIMITIVE_PROVIDER, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider", status);
+ return NULL;
+ }
+
+ BCRYPT_KEY_HANDLE key = NULL;
+
+ native_timing_start();
+ status = BCryptGenerateKeyPair(handle, &key, keysize, 0);
+ native_timing_pause();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGenerateKeyPair\n", status);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return NULL;
+ }
+
+ native_timing_restart();
+ status = BCryptFinalizeKeyPair(key, 0);
+ native_timing_stop();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptFinalizeKeyPair\n", status);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return NULL;
+ }
+
+ jobject privkey = key_to_privkey(env, key, KEYFLAG_NIST, NULL);
+ jobject pubkey = key_to_pubkey(env, key, KEYFLAG_NIST, NULL);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ BCryptDestroyKey(key);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL
+Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(
+ JNIEnv *env, jobject self, jobject params, jobject random) {
+ NTSTATUS status;
+ BCRYPT_ALG_HANDLE handle = NULL;
+ BCRYPT_KEY_HANDLE key = NULL;
+
+ jclass mscng_kpg_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Mscng");
+ jfieldID type_id = (*env)->GetFieldID(env, mscng_kpg_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring)(*env)->GetObjectField(env, self, type_id);
+ const char *type_data = (*env)->GetStringUTFChars(env, type, NULL);
+ LPCWSTR algo;
+ if (strcmp(type_data, "ECDH") == 0) {
+ algo = BCRYPT_ECDH_ALGORITHM;
+ } else if (strcmp(type_data, "ECDSA") == 0) {
+ algo = BCRYPT_ECDSA_ALGORITHM;
+ } else {
+ // unreachable
+ return NULL;
+ }
+ (*env)->ReleaseStringUTFChars(env, type, type_data);
+
+ jint keyflag;
+ NWPSTR curveName;
+ ULONG bits = init_algo(env, &handle, &keyflag, &curveName, algo, params);
+ if (bits == 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Couldn't initialize algo.");
+ return NULL;
+ }
+
+ native_timing_start();
+ status = BCryptGenerateKeyPair(handle, &key, bits, 0);
+ native_timing_pause();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGenerateKeyPair\n", status);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return NULL;
+ }
+
+ native_timing_restart();
+ status = BCryptFinalizeKeyPair(key, 0);
+ native_timing_stop();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptFinalizeKeyPair\n", status);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return NULL;
+ }
+
+ jobject privkey = key_to_privkey(env, key, keyflag, curveName);
+ jobject pubkey = key_to_pubkey(env, key, keyflag, curveName);
+
+ if (curveName) {
+ free(curveName);
+ }
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ BCryptDestroyKey(key);
+ BCryptCloseAlgorithmProvider(handle, 0);
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+static NTSTATUS init_use_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR type, jint keyflag, jbyteArray meta, jobject params) {
+ LPCWSTR ecdh_algos[] = {BCRYPT_ECDH_ALGORITHM, BCRYPT_ECDH_P256_ALGORITHM, BCRYPT_ECDH_P384_ALGORITHM, BCRYPT_ECDH_P521_ALGORITHM};
+ LPCWSTR ecdsa_algos[] = {BCRYPT_ECDSA_ALGORITHM, BCRYPT_ECDSA_P256_ALGORITHM, BCRYPT_ECDSA_P384_ALGORITHM, BCRYPT_ECDSA_P521_ALGORITHM};
+
+ LPCWSTR *algos;
+ LPCWSTR algo;
+ if (lstrcmpW(type, BCRYPT_ECDH_ALGORITHM) == 0) {
+ algos = ecdh_algos;
+ } else if (lstrcmpW(type, BCRYPT_ECDSA_ALGORITHM) == 0) {
+ algos = ecdsa_algos;
+ } else {
+ // unreachable
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ switch (keyflag) {
+ case KEYFLAG_IMPLICIT:
+ case KEYFLAG_EXPLICIT:
+ case KEYFLAG_OTHER:
+ algo = algos[0];
+ break;
+ case KEYFLAG_NIST: {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ switch (bits) {
+ case 256:
+ algo = algos[1];
+ break;
+ case 384:
+ algo = algos[2];
+ break;
+ case 521:
+ algo = algos[3];
+ break;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+ break;
+ }
+ }
+ NTSTATUS status;
+
+ if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(handle, algo, MS_PRIMITIVE_PROVIDER, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
+ return status;
+ }
+
+ switch (keyflag) {
+ case KEYFLAG_IMPLICIT: {
+ jint meta_len = (*env)->GetArrayLength(env, meta);
+ jbyte *meta_data = (*env)->GetByteArrayElements(env, meta, NULL);
+ // if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, meta_data, meta_len, 0))) {
+ // throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSetProperty(curve name)\n",
+ //status);
+ // (*env)->ReleaseByteArrayElements(env, meta, meta_data, JNI_ABORT);
+ // return status;
+ //}
+ (*env)->ReleaseByteArrayElements(env, meta, meta_data, JNI_ABORT);
+ break;
+ }
+ case KEYFLAG_EXPLICIT:
+ case KEYFLAG_OTHER: {
+ PBYTE curve;
+ ULONG curve_len = create_curve(env, params, &curve);
+ if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_PARAMETERS, curve, curve_len, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSetProperty(parameters)\n",
+ status);
+ free(curve);
+ return status;
+ }
+ free(curve);
+ break;
+ }
+ }
+ return STATUS_SUCCESS;
+}
+
+static jint get_keyflag(JNIEnv *env, jobject key) {
+ if ((*env)->IsInstanceOf(env, key, pubkey_class) || (*env)->IsInstanceOf(env, key, privkey_class)) {
+ jclass key_class = (*env)->GetObjectClass(env, key);
+ jmethodID get_flag = (*env)->GetMethodID(env, key_class, "getFlag", "()I");
+ return (*env)->CallIntMethod(env, key, get_flag);
+ } else {
+ return KEYFLAG_OTHER;
+ }
+}
+
+static jbyteArray get_meta(JNIEnv *env, jobject key) {
+ if ((*env)->IsInstanceOf(env, key, pubkey_class) || (*env)->IsInstanceOf(env, key, privkey_class)) {
+ jclass key_class = (*env)->GetObjectClass(env, key);
+ jmethodID get_meta = (*env)->GetMethodID(env, key_class, "getMeta", "()[B");
+ return (jbyteArray)(*env)->CallObjectMethod(env, key, get_meta);
+ } else {
+ return NULL;
+ }
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret__Ljava_security_interfaces_ECPublicKey_2Ljava_security_interfaces_ECPrivateKey_2Ljava_security_spec_AlgorithmParameterSpec_2(
+ JNIEnv *env, jobject self, jobject pubkey, jobject privkey, jobject params) {
+ NTSTATUS status;
+
+ jclass mscng_ka_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Mscng");
+ jfieldID type_id = (*env)->GetFieldID(env, mscng_ka_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring)(*env)->GetObjectField(env, self, type_id);
+ const char *type_data = (*env)->GetStringUTFChars(env, type, NULL);
+ LPCWSTR kdf_algo;
+ if (strcmp(type_data, "ECDHwithSHA1KDF(CNG)") == 0) {
+ kdf_algo = BCRYPT_SHA1_ALGORITHM;
+ } else if (strcmp(type_data, "ECDHwithSHA256KDF(CNG)") == 0) {
+ kdf_algo = BCRYPT_SHA256_ALGORITHM;
+ } else if (strcmp(type_data, "ECDHwithSHA384KDF(CNG)") == 0) {
+ kdf_algo = BCRYPT_SHA384_ALGORITHM;
+ } else if (strcmp(type_data, "ECDHwithSHA512KDF(CNG)") == 0) {
+ kdf_algo = BCRYPT_SHA512_ALGORITHM;
+ } else {
+ // unreachable
+ return NULL;
+ }
+ (*env)->ReleaseStringUTFChars(env, type, type_data);
+
+ BCRYPT_ALG_HANDLE kaHandle = NULL;
+
+ jint pub_flag = get_keyflag(env, pubkey);
+ if (pub_flag == KEYFLAG_OTHER) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native public key.");
+ return NULL;
+ }
+ jbyteArray meta = get_meta(env, pubkey);
+
+ if (NT_FAILURE(status = init_use_algo(env, &kaHandle, BCRYPT_ECDH_ALGORITHM, pub_flag, meta, params))) {
+ return NULL;
+ }
+
+ BCRYPT_KEY_HANDLE pkey = NULL;
+ BCRYPT_KEY_HANDLE skey = NULL;
+
+ jmethodID get_data_priv = (*env)->GetMethodID(env, pubkey_class, "getData", "()[B");
+ jbyteArray pubkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, pubkey, get_data_priv);
+
+ jint pub_length = (*env)->GetArrayLength(env, pubkey_barray);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey_barray, NULL);
+ if (NT_FAILURE(status = BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair(pub)\n", status);
+ BCryptCloseAlgorithmProvider(kaHandle, 0);
+ (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT);
+
+ jint priv_flag = get_keyflag(env, privkey);
+ if (priv_flag == KEYFLAG_OTHER) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native private key.");
+ return NULL;
+ }
+
+ jmethodID get_data_pub = (*env)->GetMethodID(env, privkey_class, "getData", "()[B");
+ jbyteArray privkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, privkey, get_data_pub);
+
+ jint priv_length = (*env)->GetArrayLength(env, privkey_barray);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey_barray, NULL);
+ if (NT_FAILURE(status = BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair(priv)\n", status);
+ BCryptCloseAlgorithmProvider(kaHandle, 0);
+ BCryptDestroyKey(pkey);
+ (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT);
+
+ BCRYPT_SECRET_HANDLE ka = NULL;
+
+ native_timing_start();
+ status = BCryptSecretAgreement(skey, pkey, &ka, 0);
+ native_timing_stop();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSecretAgreement\n", status);
+ BCryptCloseAlgorithmProvider(kaHandle, 0);
+ BCryptDestroyKey(pkey);
+ BCryptDestroyKey(skey);
+ return NULL;
+ }
+
+ BCryptBufferDesc paramList = {0};
+ BCryptBuffer kdfParams[1] = {0};
+ kdfParams[0].BufferType = KDF_HASH_ALGORITHM;
+ kdfParams[0].cbBuffer = (DWORD)((wcslen(kdf_algo) + 1) * sizeof(WCHAR));
+ kdfParams[0].pvBuffer = (PVOID)kdf_algo;
+ paramList.cBuffers = 1;
+ paramList.pBuffers = kdfParams;
+ paramList.ulVersion = BCRYPTBUFFER_VERSION;
+
+ ULONG bufSize = 0;
+ if (NT_FAILURE(status = BCryptDeriveKey(ka, BCRYPT_KDF_HASH, &paramList, NULL, 0, &bufSize, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptDeriveKey(length only)\n", status);
+ return NULL;
+ }
+
+ PBYTE derived = calloc(bufSize, 1);
+ if (NT_FAILURE(status = BCryptDeriveKey(ka, BCRYPT_KDF_HASH, &paramList, derived, bufSize, &bufSize, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptDeriveKey(whole)\n", status);
+ return NULL;
+ }
+
+ jbyteArray result = (*env)->NewByteArray(env, bufSize);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ memcpy(result_data, derived, bufSize);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ free(derived);
+ BCryptDestroyKey(pkey);
+ BCryptDestroyKey(skey);
+ BCryptDestroySecret(ka);
+ BCryptCloseAlgorithmProvider(kaHandle, 0);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL
+Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret__Ljava_security_interfaces_ECPublicKey_2Ljava_security_interfaces_ECPrivateKey_2Ljava_security_spec_AlgorithmParameterSpec_2Ljava_lang_String_2(
+ JNIEnv *env, jobject self, jobject pubkey, jobject privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+static LPCWSTR get_sighash_algo(JNIEnv *env, jobject self) {
+ jclass mscng_sig_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Mscng");
+ jfieldID type_id = (*env)->GetFieldID(env, mscng_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring)(*env)->GetObjectField(env, self, type_id);
+ const char *type_data = (*env)->GetStringUTFChars(env, type, NULL);
+ LPCWSTR hash_algo;
+ if (strcmp(type_data, "SHA1withECDSA") == 0) {
+ hash_algo = BCRYPT_SHA1_ALGORITHM;
+ } else if (strcmp(type_data, "SHA256withECDSA") == 0) {
+ hash_algo = BCRYPT_SHA256_ALGORITHM;
+ } else if (strcmp(type_data, "SHA384withECDSA") == 0) {
+ hash_algo = BCRYPT_SHA384_ALGORITHM;
+ } else if (strcmp(type_data, "SHA512withECDSA") == 0) {
+ hash_algo = BCRYPT_SHA512_ALGORITHM;
+ } else {
+ // unreachable
+ return NULL;
+ }
+ (*env)->ReleaseStringUTFChars(env, type, type_data);
+ return hash_algo;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_sign(JNIEnv *env, jobject self,
+ jbyteArray data, jobject privkey,
+ jobject params) {
+ NTSTATUS status;
+ LPCWSTR hash_algo = get_sighash_algo(env, self);
+
+ BCRYPT_ALG_HANDLE sigHandle = NULL;
+
+ jint keyflag = get_keyflag(env, privkey);
+ if (keyflag == KEYFLAG_OTHER) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native private key.");
+ return NULL;
+ }
+ jbyteArray meta = get_meta(env, privkey);
+
+ if (NT_FAILURE(status = init_use_algo(env, &sigHandle, BCRYPT_ECDSA_ALGORITHM, keyflag, meta, params))) {
+ return NULL;
+ }
+
+ if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&sigHandle, BCRYPT_ECDSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
+ return NULL;
+ }
+
+ BCRYPT_ALG_HANDLE hashHandle = NULL;
+
+ if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&hashHandle, hash_algo, NULL, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ return NULL;
+ }
+
+ DWORD dummy = 0;
+ DWORD hash_len = 0;
+ if (NT_FAILURE(status = BCryptGetProperty(hashHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hash_len, sizeof(DWORD), &dummy, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGetProperty(hash len)\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ return NULL;
+ }
+
+ PBYTE hash = calloc(hash_len, 1);
+
+ jint data_len = (*env)->GetArrayLength(env, data);
+ jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL);
+ native_timing_start();
+ status = BCryptHash(hashHandle, NULL, 0, data_bytes, data_len, hash, hash_len);
+ native_timing_pause();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptHash\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ free(hash);
+ (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT);
+
+ BCRYPT_KEY_HANDLE skey = NULL;
+
+ jmethodID get_data = (*env)->GetMethodID(env, privkey_class, "getData", "()[B");
+ jbyteArray privkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, privkey, get_data);
+
+ jint priv_length = (*env)->GetArrayLength(env, privkey_barray);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey_barray, NULL);
+ if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ free(hash);
+ (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT);
+
+ DWORD sig_len = 0;
+ native_timing_restart();
+ status = BCryptSignHash(skey, NULL, hash, hash_len, NULL, 0, &sig_len, 0);
+ native_timing_pause();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSignHash(len only)\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ free(hash);
+ return NULL;
+ }
+
+ PBYTE sig_buf = calloc(sig_len, 1);
+
+ native_timing_restart();
+ status = BCryptSignHash(skey, NULL, hash, hash_len, sig_buf, sig_len, &sig_len, 0);
+ native_timing_stop();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSignHash(do)\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ free(hash);
+ free(sig_buf);
+ return NULL;
+ }
+
+ DWORD half_len = sig_len / 2;
+ jobject sig = asn1_der_encode(env, sig_buf, half_len, sig_buf + half_len, half_len);
+
+ free(hash);
+ free(sig_buf);
+ BCryptDestroyKey(skey);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+
+ return sig;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_verify(JNIEnv *env, jobject self,
+ jbyteArray sig, jbyteArray data,
+ jobject pubkey, jobject params) {
+ NTSTATUS status;
+ LPCWSTR hash_algo = get_sighash_algo(env, self);
+
+ BCRYPT_ALG_HANDLE sigHandle = NULL;
+
+ jint keyflag = get_keyflag(env, pubkey);
+ if (keyflag == KEYFLAG_OTHER) { // TODO: This is not necessary
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native public key.");
+ return JNI_FALSE;
+ }
+ jbyteArray meta = get_meta(env, pubkey);
+
+ if (NT_FAILURE(status = init_use_algo(env, &sigHandle, BCRYPT_ECDSA_ALGORITHM, keyflag, meta, params))) {
+ return JNI_FALSE;
+ }
+
+ BCRYPT_ALG_HANDLE hashHandle = NULL;
+
+ if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&hashHandle, hash_algo, NULL, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ return JNI_FALSE;
+ }
+
+ DWORD dummy = 0;
+ DWORD hash_len = 0;
+ if (NT_FAILURE(status = BCryptGetProperty(hashHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hash_len, sizeof(DWORD), &dummy, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGetProperty(hash len)\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ return JNI_FALSE;
+ }
+
+ PBYTE hash = calloc(hash_len, 1);
+
+ jint data_len = (*env)->GetArrayLength(env, data);
+ jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL);
+ native_timing_start();
+ status = BCryptHash(hashHandle, NULL, 0, data_bytes, data_len, hash, hash_len);
+ native_timing_pause();
+
+ if (NT_FAILURE(status)) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptHash\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ free(hash);
+ (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT);
+
+ BCRYPT_KEY_HANDLE pkey = NULL;
+
+ jmethodID get_data = (*env)->GetMethodID(env, pubkey_class, "getData", "()[B");
+ jbyteArray pubkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, pubkey, get_data);
+
+ jint pub_length = (*env)->GetArrayLength(env, pubkey_barray);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey_barray, NULL);
+ if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair\n", status);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ free(hash);
+ (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ jmethodID get_bitlength = (*env)->GetMethodID(env, biginteger_class, "bitLength", "()I");
+ jint ord_bits = (*env)->CallIntMethod(env, n, get_bitlength);
+ jint ord_bytes = (ord_bits + 7) / 8;
+
+ jint sig_len = (*env)->GetArrayLength(env, sig);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, sig, NULL);
+ jbyte *r;
+ size_t rlen;
+ jbyte *s;
+ size_t slen;
+ bool decode = asn1_der_decode(env, sig, &r, &rlen, &s, &slen);
+ (*env)->ReleaseByteArrayElements(env, sig, sig_data, JNI_ABORT);
+
+ if (!decode) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error decoding sig.");
+ BCryptDestroyKey(pkey);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ free(hash);
+ return JNI_FALSE;
+ }
+
+ jbyte *r_cpy = r;
+ jbyte *s_cpy = s;
+ if (rlen > ord_bytes) {
+ r_cpy += ord_bytes - rlen;
+ }
+ if (slen > ord_bytes) {
+ s_cpy += ord_bytes - slen;
+ }
+ if (rlen < ord_bytes) {
+ r_cpy = _alloca(ord_bytes);
+ memset(r_cpy, 0, ord_bytes);
+ memcpy(r_cpy, r + (ord_bytes - rlen), ord_bytes);
+ }
+ if (slen < ord_bytes) {
+ s_cpy = _alloca(ord_bytes);
+ memset(s_cpy, 0, ord_bytes);
+ memcpy(s_cpy, s + (ord_bytes - slen), ord_bytes);
+ }
+ rlen = ord_bytes;
+ slen = ord_bytes;
+
+ UCHAR *sig_full = calloc(rlen + slen, 1);
+ memcpy(sig_full, r_cpy, rlen);
+ memcpy(sig_full + rlen, s_cpy, slen);
+ free(r);
+ free(s);
+
+ native_timing_restart();
+ NTSTATUS result = BCryptVerifySignature(pkey, NULL, hash, hash_len, sig_full, rlen + slen, 0);
+ native_timing_stop();
+
+ free(hash);
+ free(sig_full);
+ BCryptDestroyKey(pkey);
+ BCryptCloseAlgorithmProvider(hashHandle, 0);
+ BCryptCloseAlgorithmProvider(sigHandle, 0);
+
+ if (result == STATUS_SUCCESS) {
+ return JNI_TRUE;
+ } else if (result == STATUS_INVALID_SIGNATURE) {
+ return JNI_FALSE;
+ } else {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptVerifySignature\n", status);
+ return JNI_FALSE;
+ }
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/native.h b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/native.h
new file mode 100644
index 0000000..8f5b521
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/native.h
@@ -0,0 +1,2044 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class cz_crcs_ectester_standalone_libs_NativeECLibrary */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_NativeECLibrary
+#define _Included_cz_crcs_ectester_standalone_libs_NativeECLibrary
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_NativeECLibrary
+ * Method: getNativeTimingSupport
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getNativeTimingSupport
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_NativeECLibrary
+ * Method: setNativeTimingType
+ * Signature: (Ljava/lang/String;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_setNativeTimingType
+ (JNIEnv *, jobject, jstring);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_NativeECLibrary
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_NativeECLibrary
+ * Method: getNativeTimingUnit
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getNativeTimingUnit
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_NativeECLibrary
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_NativeECLibrary_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_TomcryptLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_TomcryptLib
+#define _Included_cz_crcs_ectester_standalone_libs_TomcryptLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_BotanLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_BotanLib
+#define _Included_cz_crcs_ectester_standalone_libs_BotanLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_CryptoppLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_CryptoppLib
+#define _Included_cz_crcs_ectester_standalone_libs_CryptoppLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Cryptopp
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Cryptopp_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Cryptopp
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Cryptopp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Cryptopp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Cryptopp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Cryptopp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Cryptopp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Cryptopp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Cryptopp
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Cryptopp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Cryptopp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Cryptopp
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Cryptopp
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Cryptopp
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_OpensslLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_OpensslLib
+#define _Included_cz_crcs_ectester_standalone_libs_OpensslLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Openssl
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Openssl_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Openssl
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Openssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Openssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Openssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Openssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Openssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Openssl_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Openssl
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Openssl_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_MscngLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_MscngLib
+#define _Included_cz_crcs_ectester_standalone_libs_MscngLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Mscng
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Mscng_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Mscng
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Mscng */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Mscng
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Mscng
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Mscng */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Mscng
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Mscng
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng
+ * Method: generateSecret
+ * Signature: (Ljava/security/interfaces/ECPublicKey;Ljava/security/interfaces/ECPrivateKey;Ljava/security/spec/AlgorithmParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret__Ljava_security_interfaces_ECPublicKey_2Ljava_security_interfaces_ECPrivateKey_2Ljava_security_spec_AlgorithmParameterSpec_2
+ (JNIEnv *, jobject, jobject, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng
+ * Method: generateSecret
+ * Signature: (Ljava/security/interfaces/ECPublicKey;Ljava/security/interfaces/ECPrivateKey;Ljava/security/spec/AlgorithmParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret__Ljava_security_interfaces_ECPublicKey_2Ljava_security_interfaces_ECPrivateKey_2Ljava_security_spec_AlgorithmParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jobject, jobject, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Mscng */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Mscng
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Mscng
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Mscng
+ * Method: sign
+ * Signature: ([BLjava/security/interfaces/ECPrivateKey;Ljava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_sign
+ (JNIEnv *, jobject, jbyteArray, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Mscng
+ * Method: verify
+ * Signature: ([B[BLjava/security/interfaces/ECPublicKey;Ljava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_BoringsslLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_BoringsslLib
+#define _Included_cz_crcs_ectester_standalone_libs_BoringsslLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Boringssl_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_GcryptLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_GcryptLib
+#define _Included_cz_crcs_ectester_standalone_libs_GcryptLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Gcrypt_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_MbedTLSLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_MbedTLSLib
+#define _Included_cz_crcs_ectester_standalone_libs_MbedTLSLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MbedTLSLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MbedTLSLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MbedTLSLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MbedTLSLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_MbedTLS
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024MbedTLS_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_MbedTLS
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024MbedTLS_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_MbedTLS */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_MbedTLS
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_MbedTLS
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_MbedTLS */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_MbedTLS
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_MbedTLS
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_MbedTLS */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_MbedTLS
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_MbedTLS
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_MbedTLS
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024MbedTLS_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_MbedTLS
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024MbedTLS_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_MbedTLS */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_MbedTLS
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_MbedTLS
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_MbedTLS
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024MbedTLS_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_MbedTLS
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024MbedTLS_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_IppcpLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_IppcpLib
+#define _Included_cz_crcs_ectester_standalone_libs_IppcpLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_IppcpLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_IppcpLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_IppcpLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_IppcpLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Ippcp
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Ippcp_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Ippcp
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Ippcp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Ippcp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Ippcp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Ippcp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Ippcp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Ippcp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Ippcp
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Ippcp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Ippcp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Ippcp
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Ippcp
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Ippcp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Ippcp
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Ippcp_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Ippcp */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Ippcp
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Ippcp
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Ippcp
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Ippcp_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Ippcp
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Ippcp_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_MatrixsslLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_MatrixsslLib
+#define _Included_cz_crcs_ectester_standalone_libs_MatrixsslLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MatrixsslLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MatrixsslLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MatrixsslLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MatrixsslLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Matrixssl
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Matrixssl_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Matrixssl
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Matrixssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Matrixssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Matrixssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Matrixssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Matrixssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Matrixssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Matrixssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Matrixssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Matrixssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Matrixssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Matrixssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Matrixssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Matrixssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Matrixssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Matrixssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Matrixssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Matrixssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Matrixssl
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Matrixssl_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Matrixssl
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Matrixssl_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_LibresslLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_LibresslLib
+#define _Included_cz_crcs_ectester_standalone_libs_LibresslLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_LibresslLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_LibresslLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_LibresslLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_LibresslLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Libressl
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Libressl_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Libressl
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Libressl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Libressl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Libressl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Libressl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Libressl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Libressl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Libressl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Libressl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Libressl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Libressl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Libressl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Libressl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Libressl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Libressl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Libressl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Libressl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Libressl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Libressl
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Libressl_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Libressl
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Libressl_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/nettle.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/nettle.c
new file mode 100644
index 0000000..e8d874a
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/nettle.c
@@ -0,0 +1,511 @@
+#include "native.h"
+#include <string.h>
+
+#include <nettle/version.h>
+#include <nettle/ecc.h>
+#include <nettle/ecc-curve.h>
+#include <nettle/ecdsa.h>
+#include <nettle/yarrow.h>
+#include <nettle/dsa.h>
+#include <gmp.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+static struct yarrow256_ctx yarrow;
+
+
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Nettle");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, "Nettle");
+
+ double version = NETTLE_VERSION_MAJOR + (double) NETTLE_VERSION_MINOR / 10;
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Nettle_setup(JNIEnv *env, jobject self) {
+
+ INIT_PROVIDER(env, provider_class);
+ ADD_KPG(env, self, "EC", "Nettle");
+ ADD_KA(env, self, "ECDH", "NettleECDH");
+ ADD_SIG(env, self, "NONEwithECDSA", "NettleECDSAwithNONE");
+
+ init_classes(env, "Nettle");
+
+ yarrow256_init(&yarrow, 0, NULL);
+ uint8_t file = open("/dev/random", O_RDONLY);
+ yarrow256_seed(&yarrow, YARROW256_SEED_FILE_SIZE, &file);
+ close(file);
+
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_NettleLib_getCurves(JNIEnv *env, jobject self) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+ char *curve_names[] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ for (int i = 0; i < 5; i++) {
+ jstring curve_name = (*env)->NewStringUTF(env, curve_names[i]);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_keysizeSupported(JNIEnv *env, jobject self, jint keysize) {
+ int supported[] = {192, 224, 256, 384, 521};
+ for (int i = 0; i < 5; i++) {
+ if (keysize == supported[i]) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+static const struct ecc_curve* create_curve(JNIEnv *env, const char* curve_name) {
+ const struct ecc_curve* curve = NULL;
+ if (curve_name) {
+ if (strcasecmp("secp192r1", curve_name) == 0) {
+ curve = nettle_get_secp_192r1();
+ }
+ if (strcasecmp("secp224r1", curve_name) == 0) {
+ curve = nettle_get_secp_224r1();
+ }
+ if (strcasecmp("secp256r1", curve_name) == 0) {
+ curve = nettle_get_secp_256r1();
+ }
+ if (strcasecmp("secp384r1", curve_name) == 0) {
+ curve = nettle_get_secp_384r1();
+ }
+ if (strcasecmp("secp521r1", curve_name) == 0) {
+ curve = nettle_get_secp_521r1();
+ }
+ return curve;
+ }
+ return NULL;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return JNI_FALSE;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+ return JNI_FALSE;
+
+}
+
+static jobject generate_from_curve(JNIEnv *env, const struct ecc_curve* curve, jobject spec, int byte_size) {
+
+ struct ecc_point pub;
+ struct ecc_scalar priv;
+
+ ecc_point_init(&pub, curve);
+ ecc_scalar_init(&priv, curve);
+ native_timing_start();
+ ecdsa_generate_keypair(&pub, &priv, (void *) &yarrow, (nettle_random_func *) yarrow256_random);
+ native_timing_stop();
+
+ mpz_t private_value;
+ mpz_init(private_value);
+ ecc_scalar_get(&priv, private_value);
+ size_t size = 0;
+ size_t xLen = 0;
+ size_t yLen = 0;
+ mpz_export(NULL, &size, 1, sizeof(unsigned char), 0, 0, private_value);
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, byte_size);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+
+ int diff = byte_size - size;
+ memset(key_priv, 0x00, diff);
+
+ mpz_export((unsigned char*) key_priv + diff, &size, 1, sizeof(unsigned char), 0, 0, private_value);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+
+ unsigned long key_len = 2*byte_size + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ mpz_t pub_value_x;
+ mpz_init(pub_value_x);
+ mpz_t pub_value_y;
+ mpz_init(pub_value_y);
+ ecc_point_get(&pub, pub_value_x, pub_value_y);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ key_pub[0] = 0x04;
+
+ mpz_export(NULL, &xLen, 1, sizeof(unsigned char), 0, 0, pub_value_x);
+ diff = byte_size - xLen;
+ memset(key_pub + 1, 0x00, diff);
+ mpz_export((unsigned char*) key_pub + 1+diff, &xLen, 1, sizeof(unsigned char), 0, 0, pub_value_x);
+
+ mpz_export(NULL, &yLen, 1, sizeof(unsigned char), 0, 0, pub_value_y);
+ diff = byte_size - yLen;
+ memset(key_pub + 1 + byte_size, 0x00, diff);
+ mpz_export((unsigned char*) key_pub + 1 + byte_size + diff, &yLen, 1, sizeof(unsigned char), 0, 0, pub_value_y);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ mpz_clears(private_value, pub_value_x, pub_value_y, NULL);
+ ecc_point_clear(&pub);
+ ecc_scalar_clear(&priv);
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+
+
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Nettle_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2Ljava_security_spec_AlgorithmParameterSpec_2(JNIEnv *env, jobject self, jobject params, jobject random, jobject spec) {
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return NULL;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ int byte_size;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ int byte_sizes[] = {24, 28, 32, 48, 66};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ byte_size = byte_sizes[i];
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ jobject result = generate_from_curve(env, curve, spec, byte_size);
+ return result;
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+ return NULL;
+}
+
+int barray_to_pubkey(JNIEnv *env, struct ecc_point* pubKey , jbyteArray pub) {
+ jsize pub_len = (*env)->GetArrayLength(env, pub);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
+ int pointLength = (pub_len - 1) / 2;
+ mpz_t x;
+ mpz_t y;
+ mpz_init(x);
+ mpz_init(y);
+ mpz_import(x, pointLength, 1, sizeof(unsigned char), 0, 0, pub_data+1);
+ mpz_import(y, pointLength, 1, sizeof(unsigned char), 0, 0, pub_data+1+pointLength);
+ (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT);
+ ecc_point_set(pubKey, x, y);
+ return pointLength;
+}
+
+int barray_to_privkey(JNIEnv *env, struct ecc_scalar* privKey, jbyteArray priv) {
+ jsize priv_len = (*env)->GetArrayLength(env, priv);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
+ mpz_t mp;
+ mpz_init(mp);
+ mpz_import(mp, priv_len, 1, sizeof(unsigned char), 0, 0, priv_data);
+ (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT);
+ ecc_scalar_set(privKey, mp);
+ return priv_len;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret___3B_3BLjava_security_spec_ECGenParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ int byte_sizes[] = {24, 28, 32, 48, 66};
+ int byte_size;
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ byte_size = byte_sizes[i];
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ struct ecc_scalar privScalar;
+ ecc_scalar_init(&privScalar, curve);
+ barray_to_privkey(env, &privScalar, privkey);
+
+ struct ecc_point eccPubPoint;
+ ecc_point_init(&eccPubPoint, curve);
+ barray_to_pubkey(env, &eccPubPoint, pubkey);
+
+ struct ecc_point resultPoint;
+ ecc_point_init(&resultPoint, curve);
+
+ jbyteArray result = (*env)->NewByteArray(env, byte_size);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+
+ native_timing_start();
+ ecc_point_mul(&resultPoint, &privScalar, &eccPubPoint);
+ native_timing_stop();
+
+ mpz_t x;
+ mpz_init(x);
+ ecc_point_get(&resultPoint, x, NULL);
+
+ size_t size;
+
+ mpz_export(NULL, &size, 1, sizeof(unsigned char), 0, 0, x);
+ int diff = byte_size - size;
+ memset(result_data, 0x00, diff);
+ mpz_export((unsigned char*) result_data + diff, &size, 1, sizeof(unsigned char), 0, 0, x);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+ ecc_scalar_clear(&privScalar);
+ ecc_point_clear(&eccPubPoint);
+ ecc_point_clear(&resultPoint);
+ mpz_clear(x);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Nettle_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+// credit to https://github.com/crocs-muni/ECTester/blob/master/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
+size_t signature_to_der(struct dsa_signature* signature, unsigned char *result, int byte_size) {
+ size_t r_tmpSize;
+ size_t s_tmpSize;
+ size_t sequenceSize;
+ size_t sequenceSizeSize = 0;
+ size_t wholeSize;
+
+ mpz_export(NULL, &r_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->r);
+ mpz_export(NULL, &s_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->s);
+
+ unsigned char r_tmp[r_tmpSize];
+ unsigned char s_tmp[s_tmpSize];
+ mpz_export(r_tmp, &r_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->r);
+ mpz_export(s_tmp, &s_tmpSize, 1, sizeof(unsigned char), 0, 0, signature->s);
+
+ size_t rSize = r_tmpSize + (r_tmp[0] & 0x80 ? 1 : 0);
+ size_t sSize = s_tmpSize + (s_tmp[0] & 0x80 ? 1 : 0);
+
+ sequenceSize = 2 + rSize + 2 + sSize;
+
+ if (sequenceSize > 127) {
+ size_t s = sequenceSize;
+ do {
+ sequenceSizeSize++;
+ } while ((s = s >> 8));
+ }
+
+ wholeSize = sequenceSize + sequenceSizeSize + 2;
+ if (!result) {
+ return wholeSize;
+ }
+
+ int index = 0;
+ result[index++] = 0x30;
+ if (sequenceSize < 128) {
+ result[index++] = sequenceSize;
+ } else {
+ result[index++] = sequenceSizeSize | 0x80;
+ for (size_t i = 0; i < sequenceSizeSize; i++) {
+ result[index++] = sequenceSize & (0xff << (8 * (sequenceSizeSize - i - 1)));
+ }
+ }
+ result[index++] = 0x02;
+ result[index++] = rSize;
+ if (r_tmp[0] & 0x80) {
+ result[index++] = 0x00;
+ }
+ memcpy(result + index, r_tmp, r_tmpSize);
+ index += r_tmpSize;
+ result[index++] = 0x02;
+ result[index++] = sSize;
+ if (s_tmp[0] & 0x80) {
+ result[index++] = 0x00;
+ }
+ memcpy(result + index, s_tmp, s_tmpSize);
+ return wholeSize;
+}
+
+// credit to https://github.com/crocs-muni/ECTester/blob/master/src/cz/crcs/ectester/standalone/libs/jni/c_utils.cs
+int der_to_signature(struct dsa_signature* signature, unsigned char* der) {
+ int index = 0;
+ size_t sequenceSize;
+ size_t sequenceSizeSize;
+ if (der[index++] != 0x30) {
+ return 0;
+ }
+
+ if (!(der[index] & 0x80)) {
+ sequenceSize = der[index++];
+ } else {
+ sequenceSizeSize = der[index++] & 0x7f;
+ while(sequenceSizeSize > 0) {
+ sequenceSizeSize--;
+ sequenceSize |= der[index++] << (sequenceSizeSize);
+ }
+ }
+
+ if (der[index++] != 0x02) {
+ return 0;
+ }
+
+ size_t rLength = der[index++];
+ mpz_import(signature->r, rLength, 1, sizeof(unsigned char), 0, 0, der + index);
+ index += rLength;
+ if (der[index++] != 0x02) {
+ return 0;
+ }
+ size_t sLength = der[index++];
+ mpz_import(signature->s, sLength, 1, sizeof(unsigned char), 0, 0, der + index);
+ return 1;
+
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Nettle_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ int byte_size;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ int byte_sizes[] = {24, 28, 32, 48, 66};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ byte_size = byte_sizes[i] + 1;
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ struct ecc_scalar privScalar;
+ ecc_scalar_init(&privScalar, curve);
+ barray_to_privkey(env, &privScalar, privkey);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ struct dsa_signature signature;
+ dsa_signature_init(&signature);
+
+ native_timing_start();
+ ecdsa_sign(&privScalar, (void *) &yarrow, (nettle_random_func *) yarrow256_random, data_size, (unsigned char*)data_data, &signature);
+ native_timing_stop();
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+
+ jsize sig_len = signature_to_der(&signature, NULL, byte_size);
+ jbyteArray result = (*env)->NewByteArray(env, sig_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ signature_to_der(&signature, (unsigned char *)result_data, byte_size);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ ecc_scalar_clear(&privScalar);
+ dsa_signature_clear(&signature);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Nettle_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const struct ecc_curve* curve;
+ char *curve_name[5] = {"secp192r1", "secp224r1", "secp256r1", "secp384r1", "secp521r1"};
+ for (int i = 0; i < sizeof(curve_name); i++) {
+ if (strcasecmp(utf_name, curve_name[i]) == 0) {
+ curve = create_curve(env, curve_name[i]);
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return false;
+ }
+
+ struct ecc_point eccPubPoint;
+ ecc_point_init(&eccPubPoint, curve);
+ barray_to_pubkey(env, &eccPubPoint, pubkey);
+
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+
+ struct dsa_signature eccSignature;
+ dsa_signature_init(&eccSignature);
+
+ if (!der_to_signature(&eccSignature, (unsigned char*) sig_data)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Invalid DER encoding of the signature.");
+ return false;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int result = ecdsa_verify(&eccPubPoint, data_size, (unsigned char*)data_data, &eccSignature);
+ native_timing_stop();
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ ecc_point_clear(&eccPubPoint);
+ dsa_signature_clear(&eccSignature);
+ return (result == 1) ? JNI_TRUE : JNI_FALSE;
+}
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/openssl.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/openssl.c
new file mode 100644
index 0000000..1739420
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/openssl.c
@@ -0,0 +1,584 @@
+#include "native.h"
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/opensslv.h>
+#include <openssl/objects.h>
+#include <openssl/obj_mac.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+
+
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Openssl");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, OPENSSL_VERSION_TEXT);
+ long ver_hi = (OPENSSL_VERSION_NUMBER & 0xff000000L) >> 28;
+ long ver_mid = (OPENSSL_VERSION_NUMBER & 0xff0000L) >> 20;
+ long ver_low = (OPENSSL_VERSION_NUMBER & 0xff00L) >> 12;
+ double version = (double)ver_hi + ((double)ver_mid/10) + ((double)ver_low/100);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Openssl_setup(JNIEnv *env, jobject self) {
+ OPENSSL_no_config();
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_algorithms();
+
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, self, "EC", "Openssl");
+ ADD_KA(env, self, "ECDH", "OpensslECDH");
+ ADD_SIG(env, self, "NONEwithECDSA", "OpensslECDSAwithNONE");
+
+ init_classes(env, "Openssl");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getCurves(JNIEnv *env, jobject self) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ jstring curve_name = (*env)->NewStringUTF(env, OBJ_nid2sn(curves[i].nid));
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_keysizeSupported(JNIEnv *env, jobject self, jint keysize) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ EC_GROUP *curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ EC_GROUP_clear_free(curve);
+ return JNI_TRUE;
+ }
+ EC_GROUP_free(curve);
+ }
+ return JNI_FALSE;
+}
+
+static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ int size = BN_num_bytes(bn);
+ jbyteArray bytes = (*env)->NewByteArray(env, size);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ BN_bn2bin(bn, (unsigned char *) data);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) {
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
+ jsize byte_length = (*env)->GetArrayLength(env, byte_array);
+ jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL);
+ (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static EC_GROUP *create_curve(JNIEnv *env, jobject params) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+ BIGNUM *a_bn = biginteger_to_bignum(env, a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+ BIGNUM *b_bn = biginteger_to_bignum(env, b);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+ BIGNUM *gx_bn = biginteger_to_bignum(env, gx);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+ BIGNUM *gy_bn = biginteger_to_bignum(env, gy);
+
+ EC_GROUP *result;
+ EC_POINT *g_point;
+
+ if ((*env)->IsInstanceOf(env, field, fp_field_class)) {
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ BIGNUM *p_bn = biginteger_to_bignum(env, p);
+ result = EC_GROUP_new_curve_GFp(p_bn, a_bn, b_bn, NULL);
+ BN_free(p_bn);
+ if (!result) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_new_curve_GFp.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn);
+ return NULL;
+ }
+
+ g_point = EC_POINT_new(result);
+ if(!EC_POINT_set_affine_coordinates_GFp(result, g_point, gx_bn, gy_bn, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_POINT_set_affine_coordinates_GFp.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+ } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ jmethodID get_reduction_poly = (*env)->GetMethodID(env, f2m_field_class, "getReductionPolynomial", "()Ljava/math/BigInteger;");
+ jobject red_poly = (*env)->CallObjectMethod(env, field, get_reduction_poly);
+
+ BIGNUM *p_bn = biginteger_to_bignum(env, red_poly);
+ result = EC_GROUP_new_curve_GF2m(p_bn, a_bn, b_bn, NULL);
+ BN_free(p_bn);
+ if (!result) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_new_curve_GF2m.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn);
+ return NULL;
+ }
+
+ g_point = EC_POINT_new(result);
+ if(!EC_POINT_set_affine_coordinates_GF2m(result, g_point, gx_bn, gy_bn, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_POINT_set_affine_coordinates_GF2m.");
+ BN_free(a_bn); BN_free(b_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+
+ BN_free(a_bn);
+ BN_free(b_bn);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ BIGNUM *n_bn = biginteger_to_bignum(env, n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = (*env)->CallIntMethod(env, params, get_h);
+ BIGNUM *h_bn = BN_new();
+ BN_set_word(h_bn, h);
+
+ if (!EC_GROUP_set_generator(result, g_point, n_bn, h_bn)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_set_generator.");
+ BN_free(n_bn); BN_free(h_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+
+ EC_POINT_free(g_point);
+ BN_free(gx_bn);
+ BN_free(gy_bn);
+ BN_free(n_bn);
+ BN_free(h_bn);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jboolean result = (EC_GROUP_check(curve, NULL) == 1) ? JNI_TRUE : JNI_FALSE;
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
+ int field_type = EC_METHOD_get_field_type(EC_GROUP_method_of(curve));
+ BIGNUM *a;
+ BIGNUM *b;
+
+ BIGNUM *gx;
+ BIGNUM *gy;
+ jobject field;
+
+ a = BN_new();
+ b = BN_new();
+
+ if (field_type == NID_X9_62_prime_field) {
+ BIGNUM *p = BN_new();
+ if (!EC_GROUP_get_curve_GFp(curve, p, a, b, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_curve_GFp.");
+ BN_free(p); BN_free(a); BN_free(b);
+ return NULL;
+ }
+
+ jobject p_int = bignum_to_biginteger(env, p);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int);
+
+ BN_free(p);
+
+ gx = BN_new();
+ gy = BN_new();
+ if (!EC_POINT_get_affine_coordinates_GFp(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_POINT_get_affine_coordinates_GFp.");
+ BN_free(a); BN_free(b); BN_free(gx); BN_free(gy);
+ return NULL;
+ }
+
+ } else if (field_type == NID_X9_62_characteristic_two_field) {
+ if (!EC_GROUP_get_curve_GF2m(curve, NULL, a, b, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_curve_GF2m.");
+ BN_free(a); BN_free(b);
+ return NULL;
+ }
+
+ int basis_type = EC_GROUP_get_basis_type(curve);
+ jintArray ks;
+ jint *ks_data;
+ if (basis_type == NID_X9_62_tpBasis) {
+ ks = (*env)->NewIntArray(env, 1);
+ ks_data = (*env)->GetIntArrayElements(env, ks, NULL);
+ if (!EC_GROUP_get_trinomial_basis(curve, (unsigned int *) &ks_data[0])) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_trinomial_basis.");
+ BN_free(a); BN_free(b);
+ (*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT);
+ return NULL;
+ }
+ } else if (basis_type == NID_X9_62_ppBasis) {
+ ks = (*env)->NewIntArray(env, 3);
+ ks_data = (*env)->GetIntArrayElements(env, ks, NULL);
+ if (!EC_GROUP_get_pentanomial_basis(curve, (unsigned int *) &ks_data[0], (unsigned int *) &ks_data[1], (unsigned int *) &ks_data[2])) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_pentanomial_basis.");
+ BN_free(a); BN_free(b);
+ (*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT);
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ (*env)->ReleaseIntArrayElements(env, ks, ks_data, 0);
+
+ jint m = EC_GROUP_get_degree(curve);
+
+ jmethodID f2m_field_init = (*env)->GetMethodID(env, f2m_field_class, "<init>", "(I[I)V");
+ field = (*env)->NewObject(env, f2m_field_class, f2m_field_init, m, ks);
+
+ gx = BN_new();
+ gy = BN_new();
+ if (!EC_POINT_get_affine_coordinates_GF2m(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_POINT_get_affine_coordinates_GF2m.");
+ BN_free(a); BN_free(b); BN_free(gx); BN_free(gy);
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+
+ jobject a_int = bignum_to_biginteger(env, a);
+ jobject b_int = bignum_to_biginteger(env, b);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int);
+
+ BN_free(a);
+ BN_free(b);
+
+ jobject gx_int = bignum_to_biginteger(env, gx);
+ jobject gy_int = bignum_to_biginteger(env, gy);
+
+ BN_free(gx);
+ BN_free(gy);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int);
+
+ jobject order = bignum_to_biginteger(env, EC_GROUP_get0_order(curve));
+ jint cofactor = BN_get_word(EC_GROUP_get0_cofactor(curve));
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order, cofactor);
+}
+
+static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
+ jint keysize = EC_GROUP_get_degree(curve);
+ unsigned long key_bytes = (keysize + 7) / 8;
+
+ EC_KEY *key = EC_KEY_new();
+ EC_KEY_set_group(key, curve);
+
+ native_timing_start();
+ int result = EC_KEY_generate_key(key);
+ native_timing_stop();
+
+ if (!result) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key.");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ BN_bn2binpad(EC_KEY_get0_private_key(key), (unsigned char *) key_priv, key_bytes);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ unsigned long key_len = 2*key_bytes + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, (unsigned char *) key_pub, key_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ EC_KEY_free(key);
+
+ jobject ec_param_spec = create_ec_param_spec(env, curve);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ break;
+ }
+ EC_GROUP_free(curve);
+ }
+
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Openssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize pub_len = (*env)->GetArrayLength(env, pub);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
+ EC_POINT *pub_point = EC_POINT_new(curve);
+ EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT);
+ EC_KEY_set_public_key(result, pub_point);
+ EC_POINT_free(pub_point);
+ return result;
+}
+
+EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize priv_len = (*env)->GetArrayLength(env, priv);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
+ BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT);
+ EC_KEY_set_private_key(result, s);
+ BN_free(s);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Openssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ int field_size = EC_GROUP_get_degree(curve);
+ size_t secret_len = (field_size + 7)/8;
+
+ //TODO: Do more KeyAgreements here, but will have to do the hash-fun manually,
+ // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string.
+ jbyteArray result = (*env)->NewByteArray(env, secret_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+
+ native_timing_start();
+ int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL);
+ native_timing_stop();
+
+ if (err <= 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key.");
+ EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ EC_KEY_free(pub);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Openssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Openssl_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually?
+
+ native_timing_start();
+ ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv);
+ native_timing_stop();
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ if (!signature) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign.");
+ EC_KEY_free(priv); EC_GROUP_free(curve);
+ return NULL;
+ }
+
+ jsize sig_len = i2d_ECDSA_SIG(signature, NULL);
+ jbyteArray result = (*env)->NewByteArray(env, sig_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ jbyte *result_data_ptr = result_data;
+ i2d_ECDSA_SIG(signature, (unsigned char **)&result_data_ptr);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ ECDSA_SIG_free(signature);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Openssl_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return JNI_FALSE;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+
+ jsize sig_len = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+ jbyte *sig_data_ptr = sig_data;
+ ECDSA_SIG *sig_obj = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig_data_ptr, sig_len);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub);
+ native_timing_stop();
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ if (result < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify.");
+ EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj);
+ return JNI_FALSE;
+ }
+
+ ECDSA_SIG_free(sig_obj);
+ EC_KEY_free(pub);
+ EC_GROUP_free(curve);
+ return (result == 1) ? JNI_TRUE : JNI_FALSE;
+} \ No newline at end of file
diff --git a/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
new file mode 100644
index 0000000..82592f1
--- /dev/null
+++ b/standalone/src/main/java/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
@@ -0,0 +1,465 @@
+#include "native.h"
+#include <stdio.h>
+#include <string.h>
+#include <tomcrypt.h>
+#include "c_utils.h"
+#include "c_timing.h"
+
+static prng_state ltc_prng;
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider(JNIEnv *env, jobject this) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$TomCrypt");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, "libtomcrypt " SCRYPT);
+ double version = strtod(SCRYPT, NULL);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup(JNIEnv *env, jobject this) {
+ /* Initialize libtommath as the math lib. */
+ ltc_mp = ltm_desc;
+
+ jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ jstring ec = (*env)->NewStringUTF(env, "KeyPairGenerator.EC");
+ jstring ec_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$TomCrypt");
+ (*env)->CallObjectMethod(env, this, provider_put, ec, ec_value);
+
+ jstring ecdh = (*env)->NewStringUTF(env, "KeyAgreement.ECDH");
+ jstring ecdh_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt");
+ (*env)->CallObjectMethod(env, this, provider_put, ecdh, ecdh_value);
+
+ jstring ecdsa = (*env)->NewStringUTF(env, "Signature.NONEwithECDSA");
+ jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw");
+ (*env)->CallObjectMethod(env, this, provider_put, ecdsa, ecdsa_value);
+
+ int err;
+ /* register yarrow */
+ if (register_prng(&yarrow_desc) == -1) {
+ fprintf(stderr, "Error registering Yarrow\n");
+ return;
+ }
+ /* setup the PRNG */
+ if ((err = rng_make_prng(128, find_prng("yarrow"), &ltc_prng, NULL)) != CRYPT_OK) {
+ fprintf(stderr, "Error setting up PRNG, %s\n", error_to_string(err));
+ }
+
+ init_classes(env, "TomCrypt");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves(JNIEnv *env, jobject this) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ jstring curve_name = (*env)->NewStringUTF(env, curve->name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ curve++;
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize){
+ int key_bytes = (keysize + 7) / 8;
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (curve->size == key_bytes) {
+ return JNI_TRUE;
+ }
+ curve++;
+ }
+
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported(JNIEnv *env, jobject this, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, curve, get_field);
+
+ if ((*env)->IsInstanceOf(env, field, fp_field_class)) {
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, curve, get_a);
+
+ jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;");
+ jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong)3);
+
+ jmethodID biginteger_add = (*env)->GetMethodID(env, biginteger_class, "add", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;");
+ jobject a_3 = (*env)->CallObjectMethod(env, a, biginteger_add, three);
+
+ jmethodID biginteger_equals = (*env)->GetMethodID(env, biginteger_class, "equals", "(Ljava/lang/Object;)Z");
+ jboolean eq = (*env)->CallBooleanMethod(env, p, biginteger_equals, a_3);
+ return eq;
+ } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const ltc_ecc_set_type * curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (strcasecmp(utf_name, curve->name) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ curve++;
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const ltc_ecc_set_type *curve) {
+ jstring p_string = (*env)->NewStringUTF(env, curve->prime);
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(Ljava/lang/String;I)V");
+ jobject p = (*env)->NewObject(env, biginteger_class, biginteger_init, p_string, (jint) 16);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p);
+
+ jmethodID biginteger_subtract = (*env)->GetMethodID(env, biginteger_class, "subtract", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;");
+ jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;");
+ jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong) 3);
+ jobject a = (*env)->CallObjectMethod(env, p, biginteger_subtract, three);
+
+ jstring b_string = (*env)->NewStringUTF(env, curve->B);
+ jobject b = (*env)->NewObject(env, biginteger_class, biginteger_init, b_string, (jint) 16);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a, b);
+
+ jstring gx_string = (*env)->NewStringUTF(env, curve->Gx);
+ jstring gy_string = (*env)->NewStringUTF(env, curve->Gy);
+ jobject gx = (*env)->NewObject(env, biginteger_class, biginteger_init, gx_string, (jint) 16);
+ jobject gy = (*env)->NewObject(env, biginteger_class, biginteger_init, gy_string, (jint) 16);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy);
+
+ jstring n_string = (*env)->NewStringUTF(env, curve->order);
+ jobject n = (*env)->NewObject(env, biginteger_class, biginteger_init, n_string, (jint) 16);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, (jint) 1);
+}
+
+static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ jint bytes = (bits + 7) / 8;
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ jmethodID get_bitlength = (*env)->GetMethodID(env, biginteger_class, "bitLength", "()I");
+ jint ord_bits = (*env)->CallIntMethod(env, n, get_bitlength);
+ jint ord_bytes = (ord_bits + 7) / 8;
+
+ ltc_ecc_set_type *curve = calloc(sizeof(ltc_ecc_set_type), 1);
+ curve->size = bytes;
+ curve->name = "";
+ curve->prime = biginteger_to_hex(env, p, bytes);
+ curve->B = biginteger_to_hex(env, b, bytes);
+ curve->order = biginteger_to_hex(env, n, ord_bytes);
+ curve->Gx = biginteger_to_hex(env, gx, bytes);
+ curve->Gy = biginteger_to_hex(env, gy, bytes);
+
+ return curve;
+}
+
+static void free_curve(ltc_ecc_set_type *curve) {
+ if (curve) {
+ free((void*)curve->prime);
+ free((void*)curve->B);
+ free((void*)curve->order);
+ free((void*)curve->Gx);
+ free((void*)curve->Gy);
+ free(curve);
+ }
+}
+
+static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) {
+ ecc_key key;
+
+ native_timing_start();
+ int err = ecc_make_key_ex(&ltc_prng, find_prng("yarrow"), &key, curve);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ return NULL;
+ }
+ unsigned long key_len = 2*curve->size + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ ecc_ansi_x963_export(&key, (unsigned char *) key_pub, &key_len);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ jobject ec_param_spec = create_ec_param_spec(env, curve);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, curve->size);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ ltc_mp.unsigned_write(key.k, (unsigned char *) key_priv);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ ecc_free(&key);
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random){
+ int key_bytes = (keysize + 7) / 8;
+
+ const ltc_ecc_set_type *curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (curve->size == key_bytes) {
+ break;
+ }
+ curve++;
+ }
+
+ if (curve->size == 0) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ return generate_from_curve(env, curve);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random){
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+ jobject result = generate_from_curve(env, curve);
+ free_curve(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ const ltc_ecc_set_type* curve = ltc_ecc_sets;
+ while (curve->size != 0) {
+ if (strcasecmp(utf_name, curve->name) == 0) {
+ break;
+ }
+ curve++;
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+
+ return generate_from_curve(env, curve);
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ecc_set_type *curve, ecc_key *out) {
+ jsize priv_size = (*env)->GetArrayLength(env, privkey);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL);
+
+ if (curve->size != priv_size) {
+ throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the private key size.");
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ out->type = PK_PRIVATE;
+ out->idx = -1;
+ out->dp = curve;
+ ltc_mp.init(&out->k);
+ ltc_mp.unsigned_read(out->k, (unsigned char *) priv_data, (unsigned long) curve->size);
+
+ (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
+ return JNI_TRUE;
+}
+
+static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_set_type *curve, ecc_key *out) {
+ jsize pub_size = (*env)->GetArrayLength(env, pubkey);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL);
+
+ if (curve->size != (pub_size - 1) / 2) {
+ throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the public key size.");
+ (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ out->type = PK_PUBLIC;
+ out->idx = -1;
+ out->dp = curve;
+ ltc_init_multi(&out->pubkey.x, &out->pubkey.y, &out->pubkey.z, NULL);
+ ltc_mp.set_int(out->pubkey.z, 1);
+ ltc_mp.unsigned_read(out->pubkey.x, (unsigned char *) pub_data + 1, (unsigned long) curve->size);
+ ltc_mp.unsigned_read(out->pubkey.y, (unsigned char *) pub_data + 1 + curve->size, (unsigned long) curve->size);
+
+ (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params){
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key pub;
+ if (!pubkey_from_bytes(env, pubkey, curve, &pub)) {
+ free_curve(curve);
+ return NULL;
+ }
+
+ ecc_key priv;
+ if (!privkey_from_bytes(env, privkey, curve, &priv)) {
+ free_curve(curve);
+ return NULL;
+ }
+
+ unsigned char result[curve->size];
+ unsigned long output_len = curve->size;
+
+ native_timing_start();
+ int err = ecc_shared_secret(&priv, &pub, result, &output_len);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ free_curve(curve);
+ return NULL;
+ }
+
+ jbyteArray output = (*env)->NewByteArray(env, curve->size);
+ jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL);
+ memcpy(output_data, result, curve->size);
+ (*env)->ReleaseByteArrayElements(env, output, output_data, 0);
+
+ ltc_cleanup_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, &priv.k, NULL);
+ free_curve(curve);
+ return output;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key priv;
+ if (!privkey_from_bytes(env, privkey, curve, &priv)) {
+ free_curve(curve);
+ return NULL;
+ }
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ unsigned char result[curve->size*4];
+ unsigned long output_len = curve->size*4;
+
+ native_timing_start();
+ int err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, &ltc_prng, find_prng("yarrow"), &priv);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ free_curve(curve);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ return NULL;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ jbyteArray output = (*env)->NewByteArray(env, output_len);
+ jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL);
+ memcpy(output_data, result, output_len);
+ (*env)->ReleaseByteArrayElements(env, output, output_data, 0);
+
+ free_curve(curve);
+ return output;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ ltc_ecc_set_type *curve = create_curve(env, params);
+
+ ecc_key pub;
+ if (!pubkey_from_bytes(env, pubkey, curve, &pub)) {
+ free_curve(curve);
+ return JNI_FALSE;
+ }
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ jsize sig_size = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+
+ int result;
+ native_timing_start();
+ int err = ecc_verify_hash((unsigned char *) sig_data, sig_size, (unsigned char *) data_data, data_size, &result, &pub);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
+ throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
+ free_curve(curve);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+ free_curve(curve);
+ return result;
+} \ No newline at end of file
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..c061da6
--- /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() == javacard.security.KeyPair.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);
+ }
+}