diff options
| author | J08nY | 2024-03-22 23:58:55 +0100 |
|---|---|---|
| committer | J08nY | 2024-03-25 14:52:43 +0100 |
| commit | 73af477a8774e1ede5dd8de6491eb353dc0b12bd (patch) | |
| tree | 2d4e3b19bc5fb55308b886032312be76341736d4 /standalone | |
| parent | 64b95fa059295e1dc23371c849f2302c1c18f5b4 (diff) | |
| download | ECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.tar.gz ECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.tar.zst ECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.zip | |
Diffstat (limited to 'standalone')
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, ¶mLength); + + // 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, ¶mLength); + + // 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, ¶mList, 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, ¶mList, 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"), <c_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(<c_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, <c_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); + } +} |
