aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/standalone
diff options
context:
space:
mode:
authorJ08nY2018-11-28 01:04:31 +0100
committerJ08nY2018-11-28 01:04:31 +0100
commitebe40e2fdd5e28cdabe05250422f3149e188641a (patch)
treefbf29423e8053c6a7267d600d1630fefb1bf1a1b /src/cz/crcs/ectester/standalone
parent7e9917742785a9fd532a52231e95ddad5775555f (diff)
parent12845c8c41eff5f598dc8e843920f5bb4638775d (diff)
downloadECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.gz
ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.zst
ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.zip
Merge branch 'devel'
Diffstat (limited to 'src/cz/crcs/ectester/standalone')
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java335
-rw-r--r--src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java23
-rw-r--r--src/cz/crcs/ectester/standalone/consts/SignatureIdent.java29
-rw-r--r--src/cz/crcs/ectester/standalone/libs/BoringsslLib.java28
-rw-r--r--src/cz/crcs/ectester/standalone/libs/BotanLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/CryptoppLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/GcryptLib.java29
-rw-r--r--src/cz/crcs/ectester/standalone/libs/MscngLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java91
-rw-r--r--src/cz/crcs/ectester/standalone/libs/OpensslLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/TomcryptLib.java10
-rw-r--r--src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java18
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/Makefile91
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java43
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java36
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java20
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java112
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/boringssl.c528
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/botan.cpp70
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_timing.c57
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_timing.h38
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.c107
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.h11
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp39
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c635
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/mscng.c12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/native.h530
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/openssl.c66
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c57
-rw-r--r--src/cz/crcs/ectester/standalone/output/TextTestWriter.java5
33 files changed, 2822 insertions, 270 deletions
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 1d7b821..e19377d 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -28,6 +28,7 @@ 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;
@@ -49,6 +50,7 @@ import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.PrintStream;
import java.nio.file.Files;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
@@ -66,7 +68,17 @@ import java.util.stream.Collectors;
* @version v0.3.0
*/
public class ECTesterStandalone {
- private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib(), new MscngLib()};
+ private ProviderECLibrary[] libs = new ProviderECLibrary[]{
+ new SunECLib(),
+ new BouncyCastleLib(),
+ new TomcryptLib(),
+ new BotanLib(),
+ new CryptoppLib(),
+ new OpensslLib(),
+ new BoringsslLib(),
+ new GcryptLib(),
+ new MscngLib(),
+ new WolfCryptLib()};
private Config cfg;
private Options opts = new Options();
@@ -140,6 +152,7 @@ public class ECTesterStandalone {
Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).build();
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).build();
Option bits = Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build();
+ Option output = Option.builder("o").longOpt("output").desc("Output into file <output_file>.").hasArgs().argName("output_file").optionalArg(false).build();
Options testOpts = new Options();
testOpts.addOption(bits);
@@ -159,9 +172,12 @@ public class ECTesterStandalone {
ecdhOpts.addOption(bits);
ecdhOpts.addOption(namedCurve);
ecdhOpts.addOption(curveName);
+ ecdhOpts.addOption(output);
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.addOption(Option.builder().longOpt("fixed-private").desc("Perform ECDH with fixed private key.").build());
+ 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);
@@ -169,6 +185,7 @@ public class ECTesterStandalone {
ecdsaOpts.addOption(bits);
ecdsaOpts.addOption(namedCurve);
ecdsaOpts.addOption(curveName);
+ ecdhOpts.addOption(output);
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());
@@ -179,6 +196,7 @@ public class ECTesterStandalone {
generateOpts.addOption(bits);
generateOpts.addOption(namedCurve);
generateOpts.addOption(curveName);
+ ecdhOpts.addOption(output);
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.");
@@ -186,6 +204,7 @@ public class ECTesterStandalone {
Options exportOpts = new Options();
exportOpts.addOption(bits);
+ ecdhOpts.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);
@@ -222,6 +241,7 @@ public class ECTesterStandalone {
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- Supports native timing: ") + lib.supportsNativeTiming());
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())));
@@ -259,7 +279,7 @@ public class ECTesterStandalone {
/**
*
*/
- private void ecdh() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
+ private void ecdh() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, FileNotFoundException {
ProviderECLibrary lib = cfg.selected;
String algo = cli.getOptionValue("ecdh.type", "ECDH");
@@ -292,63 +312,90 @@ public class ECTesterStandalone {
if (kaIdent == null || kpIdent == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- 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);
+ }
+
+ 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);
+ }
- System.out.println("index;nanotime;pubW;privS;secret");
+ PrintStream out;
+ if (cli.hasOption("ecdh.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdh.output")));
+ } else {
+ out = System.out;
+ }
- int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1"));
- for (int i = 0; i < amount; ++i) {
- KeyPair one = kpg.genKeyPair();
- KeyPair other = kpg.genKeyPair();
+ out.println("index;time[nano];pubW;privS;secret");
- ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
- ECPublicKey pubkey = (ECPublicKey) other.getPublic();
+ KeyPair one = null;
+ if (cli.hasOption("ecdh.fixed-private")) {
+ one = kpg.genKeyPair();
+ }
+ KeyPair other = null;
+ if (cli.hasOption("ecdh.fixed-public")) {
+ other = kpg.genKeyPair();
+ }
- long elapsed = -System.nanoTime();
- if (spec != null) {
- 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();
- ka = kaIdent.getInstance(lib.getProvider());
+ int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1"));
+ for (int i = 0; i < amount; ++i) {
+ if (!cli.hasOption("ecdh.fixed-private")) {
+ one = kpg.genKeyPair();
+ }
+ if (!cli.hasOption("ecdh.fixed-public")) {
+ other = kpg.genKeyPair();
+ }
+
+ ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
+ ECPublicKey pubkey = (ECPublicKey) other.getPublic();
- 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);
- System.out.println(String.format("%d;%d;%s;%s;%s", i, elapsed, pub, priv, dh));
+ long elapsed = -System.nanoTime();
+ if (spec instanceof ECParameterSpec) {
+ 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.supportsNativeTiming()) {
+ 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();
}
}
@@ -405,61 +452,76 @@ public class ECTesterStandalone {
if (sigIdent == null || kpIdent == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- Signature sig = sigIdent.getInstance(lib.getProvider());
- KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
- 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;
- }
- kpg.initialize(curve.toSpec());
- } else if (cli.hasOption("ecdsa.curve-name")) {
- String curveName = cli.getOptionValue("ecdsa.curve-name");
- kpg.initialize(new ECGenParameterSpec(curveName));
+ }
+ Signature sig = sigIdent.getInstance(lib.getProvider());
+ KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ 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;
}
+ kpg.initialize(curve.toSpec());
+ } else if (cli.hasOption("ecdsa.curve-name")) {
+ String curveName = cli.getOptionValue("ecdsa.curve-name");
+ kpg.initialize(new ECGenParameterSpec(curveName));
+ }
- System.out.println("index;data;signtime;verifytime;pubW;privS;signature;verified");
-
- int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1"));
- for (int i = 0; i < amount; ++i) {
- KeyPair one = kpg.genKeyPair();
+ PrintStream out;
+ if (cli.hasOption("ecdsa.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdh.output")));
+ } else {
+ out = System.out;
+ }
- ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
- ECPublicKey pubkey = (ECPublicKey) one.getPublic();
+ out.println("index;data;signTime[nano];verifyTime[nano];pubW;privS;signature;verified");
- sig.initSign(privkey);
- sig.update(data);
+ int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1"));
+ for (int i = 0; i < amount; ++i) {
+ KeyPair one = kpg.genKeyPair();
- long signTime = -System.nanoTime();
- byte[] signature = sig.sign();
- signTime += System.nanoTime();
+ ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
+ ECPublicKey pubkey = (ECPublicKey) one.getPublic();
- sig.initVerify(pubkey);
- sig.update(data);
+ sig.initSign(privkey);
+ sig.update(data);
- long verifyTime = -System.nanoTime();
- boolean verified = sig.verify(signature);
- verifyTime += System.nanoTime();
+ long signTime = -System.nanoTime();
+ byte[] signature = sig.sign();
+ signTime += System.nanoTime();
+ if (lib.supportsNativeTiming()) {
+ signTime = lib.getLastNativeTiming();
+ }
+ sig.initVerify(pubkey);
+ sig.update(data);
- 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);
- System.out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0));
+ long verifyTime = -System.nanoTime();
+ boolean verified = sig.verify(signature);
+ verifyTime += System.nanoTime();
+ if (lib.supportsNativeTiming()) {
+ 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);
+ out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0));
+ }
+
+ if (cli.hasOption("ecdsa.output")) {
+ out.close();
}
}
/**
*
*/
- private void generate() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ private void generate() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, FileNotFoundException {
ProviderECLibrary lib = cfg.selected;
KeyPairGeneratorIdent ident = null;
String algo = cli.getOptionValue("generate.type", "EC");
@@ -471,37 +533,51 @@ public class ECTesterStandalone {
}
if (ident == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- 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));
+ }
+ 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;
}
- System.out.println("index;nanotime;pubW;privS");
+ kpg.initialize(curve.toSpec());
+ } else if (cli.hasOption("generate.curve-name")) {
+ String curveName = cli.getOptionValue("generate.curve-name");
+ kpg.initialize(new ECGenParameterSpec(curveName));
+ }
- int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1"));
- for (int i = 0; i < amount; ++i) {
- long elapsed = -System.nanoTime();
- KeyPair kp = kpg.genKeyPair();
- elapsed += System.nanoTime();
- ECPublicKey publicKey = (ECPublicKey) kp.getPublic();
- ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+ PrintStream out;
+ if (cli.hasOption("generate.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdh.output")));
+ } else {
+ out = System.out;
+ }
- String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false);
- String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false);
- System.out.println(String.format("%d;%d;%s;%s", i, elapsed, pub, priv));
+ out.println("index;time[nano];pubW;privS");
+
+ 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.supportsNativeTiming()) {
+ 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();
}
}
@@ -545,19 +621,18 @@ public class ECTesterStandalone {
}
if (ident == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- 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);
}
+ 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) {
diff --git a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
index 66d8235..808f298 100644
--- a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
+++ b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
@@ -11,6 +11,8 @@ import java.util.List;
*/
public class KeyAgreementIdent extends Ident {
private boolean requiresKeyAlgo;
+ private String kdf;
+ private String algo;
private static final List<KeyAgreementIdent> ALL = new LinkedList<>();
@@ -73,6 +75,19 @@ public class KeyAgreementIdent extends Ident {
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) {
@@ -84,6 +99,14 @@ public class KeyAgreementIdent extends Ident {
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 {
diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
index dea8abe..e40731b 100644
--- a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
+++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
@@ -10,6 +10,9 @@ 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 {
@@ -52,9 +55,8 @@ public class SignatureIdent extends Ident {
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
- ALL.add(new SignatureIdent("ECDDSA", "DETECDSA", "ECDETDSA"));
- ALL.add(new SignatureIdent("SHA1withECDDSA", "SHA1withDETECDSA"));
+ // 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"));
@@ -92,6 +94,19 @@ public class SignatureIdent extends Ident {
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);
+ }
+ }
+ }
}
public Signature getInstance(Provider provider) throws NoSuchAlgorithmException {
@@ -105,4 +120,12 @@ public class SignatureIdent extends Ident {
instance.getProvider();
return instance;
}
+
+ public String getHashAlgo() {
+ return hash;
+ }
+
+ public String getSigType() {
+ return sig;
+ }
}
diff --git a/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java
new file mode 100644
index 0000000..35a48a8
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java
@@ -0,0 +1,28 @@
+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
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/BotanLib.java b/src/cz/crcs/ectester/standalone/libs/BotanLib.java
index cd28791..34fb178 100644
--- a/src/cz/crcs/ectester/standalone/libs/BotanLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/BotanLib.java
@@ -13,6 +13,15 @@ public class BotanLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java
index 5112d7d..5153df5 100644
--- a/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java
@@ -13,6 +13,15 @@ public class CryptoppLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/GcryptLib.java b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java
new file mode 100644
index 0000000..ef20f97
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java
@@ -0,0 +1,29 @@
+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
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/MscngLib.java b/src/cz/crcs/ectester/standalone/libs/MscngLib.java
index 527a65b..354199a 100644
--- a/src/cz/crcs/ectester/standalone/libs/MscngLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/MscngLib.java
@@ -13,6 +13,15 @@ public class MscngLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
index 6b98cc1..7870377 100644
--- a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
+++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
@@ -47,39 +47,19 @@ public abstract class NativeECLibrary extends ProviderECLibrary {
appData = Paths.get(System.getProperty("user.home"), ".local", "share");
}
}
+ /* Resolve and create the ECTester directories in appData. */
Path libDir = appData.resolve("ECTesterStandalone");
File libDirFile = libDir.toFile();
+ Path libReqDir = libDir.resolve("lib");
+ File libReqDirFile = libReqDir.toFile();
Path libPath = libDir.resolve(resource + "." + suffix);
- File libFile = libPath.toFile();
- URL jarURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource + "." + suffix);
- if (jarURL == null) {
- return false;
- }
- URLConnection jarConnection = jarURL.openConnection();
-
- /* Only write the file if it does not exist,
- * or if the existing one is older than the
- * one in the JAR.
- */
- boolean write = false;
- if (libDirFile.isDirectory() && libFile.isFile()) {
- long jarModified = jarConnection.getLastModified();
+ /* Create directory for shims and for requirements. */
+ libDirFile.mkdirs();
+ libReqDirFile.mkdirs();
- long libModified = Files.getLastModifiedTime(libPath).toMillis();
- if (jarModified > libModified) {
- write = true;
- }
- } else {
- libDir.toFile().mkdirs();
- libFile.createNewFile();
- write = true;
- }
-
- if (write) {
- Files.copy(jarConnection.getInputStream(), libPath, StandardCopyOption.REPLACE_EXISTING);
- }
- jarConnection.getInputStream().close();
+ /* Write the shim. */
+ writeNewer(resource + "." + suffix, libPath);
/*
* Need to hack in /usr/local/lib to path.
@@ -98,12 +78,24 @@ public abstract class NativeECLibrary extends ProviderECLibrary {
}
}
- for (String requirement : requriements) {
- System.loadLibrary(requirement);
- }
-
- if (suffix.equals("so")) {
- System.setProperty("java.library.path", path);
+ /* 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);
+ writeNewer(requirement, reqPath);
+ System.load(reqPath.toString());
+ } else {
+ System.loadLibrary(requirement);
+ }
+ }
+ } catch (UnsatisfiedLinkError ule) {
+ return false;
+ } finally {
+ if (suffix.equals("so")) {
+ System.setProperty("java.library.path", path);
+ }
}
System.load(libPath.toString());
@@ -116,5 +108,36 @@ public abstract class NativeECLibrary extends ProviderECLibrary {
return false;
}
+ private boolean isNewer(URLConnection jarConn, Path realPath) throws IOException {
+ if (realPath.toFile().isFile()) {
+ long jarModified = jarConn.getLastModified();
+ long realModified = Files.getLastModifiedTime(realPath).toMillis();
+ return jarModified > realModified;
+ }
+ return true;
+ }
+
+ private boolean writeNewer(String resource, Path outPath) throws IOException {
+ URL reqURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource);
+ if (reqURL == null) {
+ return false;
+ }
+ URLConnection reqConn = reqURL.openConnection();
+ if (isNewer(reqConn, outPath)) {
+ Files.copy(reqConn.getInputStream(), outPath, StandardCopyOption.REPLACE_EXISTING);
+ }
+ reqConn.getInputStream().close();
+ return true;
+ }
+
+ @Override
+ public abstract boolean supportsNativeTiming();
+
+ @Override
+ public abstract long getNativeTimingResolution();
+
+ @Override
+ public abstract long getLastNativeTiming();
+
abstract Provider createProvider();
}
diff --git a/src/cz/crcs/ectester/standalone/libs/OpensslLib.java b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java
index e558336..4f44a2a 100644
--- a/src/cz/crcs/ectester/standalone/libs/OpensslLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java
@@ -12,6 +12,15 @@ public class OpensslLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
index 9108eaf..83a9dc9 100644
--- a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
+++ b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
@@ -62,6 +62,18 @@ public abstract class ProviderECLibrary implements ECLibrary {
return results;
}
+ public boolean supportsNativeTiming() {
+ return false;
+ }
+
+ public long getNativeTimingResolution() {
+ return 0;
+ }
+
+ public long getLastNativeTiming() {
+ return 0;
+ }
+
@Override
public Set<KeyAgreementIdent> getKAs() {
return getIdents("KeyAgreement", KeyAgreementIdent::get);
diff --git a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java
index 78db00e..6ac74c9 100644
--- a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java
@@ -13,6 +13,16 @@ public class TomcryptLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java b/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
new file mode 100644
index 0000000..b58eb91
--- /dev/null
+++ b/src/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/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
index 006a3b1..c8ab47b 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile
+++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
@@ -1,3 +1,28 @@
+###############################################################################
+## 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)
@@ -24,56 +49,55 @@ ifeq ($(JNI_PLATFORM),)
else
ifeq ($(findstring linux,$(TARGETTRIPLET)),linux)
JNI_PLATFORM:= linux
- # add more checks here
endif
endif
endif
JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)
-LOCAL_INCLUDES = /usr/local/include
-LOCAL_LIBS = /usr/local/lib
-
-CC?=gcc
-CXX?=g++
-STRIP?=strip
-
-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
- LFLAGS+=-g
- CXXFLAGS+=-g
-else
- CFLAGS+=-O2
- LFLAGS+=-O2
- CXXFLAGS+=-O2
-endif
+###############################################################################
+## Targets.
-all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so
+all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so boringssl_provider.so gcrypt_provider.so
# Common utils
c_utils.o: c_utils.c
$(CC) $(CFLAGS) -c $<
+c_timing.o: c_timing.c
+ $(CC) $(CFLAGS) -c $<
+
cpp_utils.o: cpp_utils.cpp
$(CXX) $(CXXFLAGS) -c $<
# OpenSSL shim
-openssl_provider.so: openssl.o c_utils.o
+openssl_provider.so: openssl.o c_utils.o c_timing.o
$(CC) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs openssl)
openssl.o: openssl.c
$(CC) $(shell pkg-config --cflags openssl) $(CFLAGS) -c $<
+# BoringSSL shim
+boringssl_provider.so: boringssl.o c_utils.o c_timing.o
+ $(CC) $(LFLAGS) -o $@ $^ -L. ../../../../../../../ext/boringssl/build/crypto/libcrypto.so
+ cp ../../../../../../../ext/boringssl/build/crypto/libcrypto.so lib_boringssl.so
+
+boringssl.o: boringssl.c
+ $(CC) -I../../../../../../../ext/boringssl/include/ $(CFLAGS) -c $<
+
+
+# libgcrypt shim
+gcrypt_provider.so: gcrypt.o c_utils.o c_timing.o
+ $(CC) $(LFLAGS) -o $@ $^ -L. $(shell libgcrypt-config --libs)
+
+gcrypt.o: gcrypt.c
+ $(CC) $(shell libgcrypt-config --cflags) $(CFLAGS) -c $<
+
+
# Libtomcrypt shim
-tomcrypt_provider.so: tomcrypt.o c_utils.o
+tomcrypt_provider.so: tomcrypt.o c_utils.o c_timing.o
$(CC) $(LFLAGS) -o $@ $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt)
tomcrypt.o: tomcrypt.c
@@ -81,7 +105,7 @@ tomcrypt.o: tomcrypt.c
# Botan-2 shim
-botan_provider.so: botan.o cpp_utils.o
+botan_provider.so: botan.o cpp_utils.o c_timing.o
$(CXX) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs botan-2)
botan.o: botan.cpp
@@ -89,15 +113,24 @@ botan.o: botan.cpp
# Crypto++ shim
-cryptopp_provider.so: cryptopp.o cpp_utils.o
+cryptopp_provider.so: cryptopp.o cpp_utils.o c_timing.o
$(CXX) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs libcrypto++)
cryptopp.o: cryptopp.cpp
$(CXX) $(shell pkg-config --cflags libcrypto++) $(CXXFLAGS) -c $<
+help:
+ @echo "# This makefile builds the JNI shims necessary to test native libraries."
+ @echo "# Targets:"
+ @echo " - openssl_provider.so"
+ @echo " - boringssl_provider.so"
+ @echo " - gcrypt_provider.so"
+ @echo " - tomcrypt_provider.so"
+ @echo " - botan_provider.so"
+ @echo " - cryptopp_provider.so"
clean:
rm -rf *.o
rm -rf *.so
-.PHONY: all clean \ No newline at end of file
+.PHONY: all help clean \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
index 4cd4a9d..6d8101f 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -85,6 +85,18 @@ public abstract class NativeECPrivateKey implements ECPrivateKey {
}
}
+ public static class Boringssl extends Raw {
+ public Boringssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Gcrypt extends Raw {
+ public Gcrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
public static class Mscng extends Raw {
// 0 -> implicit (meta = curveName UTF16, header = full);
// 1 -> explicit (meta = null, header = full);
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
index 33dd3ef..dcb8b3f 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
@@ -86,6 +86,18 @@ public abstract class NativeECPublicKey implements ECPublicKey {
}
}
+ public static class Boringssl extends ANSIX962 {
+ public Boringssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Gcrypt extends ANSIX962 {
+ public Gcrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
public static class Mscng extends ANSIX962 {
// 0 -> implicit (meta = curveName UTF16, header = full);
// 1 -> explicit (meta = null, header = full);
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
index fdbdccf..7b531f5 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -65,7 +65,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
@Override
protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
if (!(params instanceof ECParameterSpec)) {
- throw new InvalidAlgorithmParameterException();
+ throw new InvalidAlgorithmParameterException(params.toString());
}
engineInit(key, random);
this.params = params;
@@ -234,6 +234,47 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
}
}
+ 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;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
index aa83479..78656fc 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
@@ -180,6 +180,42 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
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;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
index fef2930..99baa97 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
@@ -64,6 +64,26 @@ public abstract class NativeProvider extends Provider {
native void setup();
}
+ public static class Boringssl extends NativeProvider {
+
+ public Boringssl(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ public static class Gcrypt extends NativeProvider {
+
+ public Gcrypt(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
public static class Mscng extends NativeProvider {
public Mscng(String name, double version, String info) {
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
index 602b1c4..f2b1ab9 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
@@ -328,6 +328,118 @@ public abstract class NativeSignatureSpi extends SignatureSpi {
}
}
+ 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 Mscng extends ExtendedSignatureSpi {
private String type;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c
new file mode 100644
index 0000000..0484d28
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c
@@ -0,0 +1,528 @@
+#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;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
index 207532d..813b9f8 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
+++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
@@ -17,8 +17,10 @@
#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. */
@@ -145,7 +147,7 @@ static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) {
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 uint8_t*) byte_data, byte_length);
+ Botan::BigInt result((unsigned char *) byte_data, byte_length);
env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT);
return result;
}
@@ -157,10 +159,6 @@ static Botan::EC_Group group_from_params(JNIEnv *env, jobject params) {
jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
jobject field = env->CallObjectMethod(elliptic_curve, get_field);
-
- jmethodID get_bits = env->GetMethodID(fp_field_class, "getFieldSize", "()I");
- jint bits = env->CallIntMethod(field, get_bits);
- jint bytes = (bits + 7) / 8;
jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
jobject a = env->CallObjectMethod(elliptic_curve, get_a);
@@ -238,8 +236,6 @@ static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) {
}
static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) {
- Botan::AutoSeeded_RNG rng;
-
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);
@@ -249,6 +245,7 @@ static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group gr
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") {
@@ -258,6 +255,7 @@ static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group gr
} 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;
@@ -299,7 +297,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai
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 == keysize) {
+ 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);
}
@@ -349,11 +347,9 @@ jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteAr
jsize privkey_length = env->GetArrayLength(privkey);
jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
- Botan::BigInt privkey_scalar((unsigned uint8_t*) privkey_data, privkey_length);
+ Botan::BigInt privkey_scalar((unsigned char *) privkey_data, privkey_length);
env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
- Botan::AutoSeeded_RNG rng;
-
Botan::ECDH_PrivateKey skey(rng, curve_group, privkey_scalar);
jsize pubkey_length = env->GetArrayLength(pubkey);
@@ -378,7 +374,9 @@ jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteAr
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;
@@ -419,8 +417,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length);
env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT);
- Botan::AutoSeeded_RNG rng;
-
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);
@@ -430,28 +426,30 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, curve_group, privkey_scalar);
}
- std::string kdf;
+ std::string emsa;
if (type_str.find("NONE") != std::string::npos) {
- kdf = "Raw";
+ emsa = "Raw";
} else if (type_str.find("SHA1") != std::string::npos) {
- kdf = "EMSA1(SHA-1)";
+ emsa = "EMSA1(SHA-1)";
} else if (type_str.find("SHA224") != std::string::npos) {
- kdf = "EMSA1(SHA-224)";
+ emsa = "EMSA1(SHA-224)";
} else if (type_str.find("SHA256") != std::string::npos) {
- kdf = "EMSA1(SHA-256)";
+ emsa = "EMSA1(SHA-256)";
} else if (type_str.find("SHA384") != std::string::npos) {
- kdf = "EMSA1(SHA-384)";
+ emsa = "EMSA1(SHA-384)";
} else if (type_str.find("SHA512") != std::string::npos) {
- kdf = "EMSA1(SHA-512)";
+ emsa = "EMSA1(SHA-512)";
}
- Botan::PK_Signer signer(*skey, rng, kdf, Botan::DER_SEQUENCE);
+ 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);
@@ -491,22 +489,22 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
pkey = std::make_unique<Botan::ECGDSA_PublicKey>(curve_group, public_point);
}
- std::string kdf;
+ std::string emsa;
if (type_str.find("NONE") != std::string::npos) {
- kdf = "Raw";
+ emsa = "Raw";
} else if (type_str.find("SHA1") != std::string::npos) {
- kdf = "EMSA1(SHA-1)";
+ emsa = "EMSA1(SHA-1)";
} else if (type_str.find("SHA224") != std::string::npos) {
- kdf = "EMSA1(SHA-224)";
+ emsa = "EMSA1(SHA-224)";
} else if (type_str.find("SHA256") != std::string::npos) {
- kdf = "EMSA1(SHA-256)";
+ emsa = "EMSA1(SHA-256)";
} else if (type_str.find("SHA384") != std::string::npos) {
- kdf = "EMSA1(SHA-384)";
+ emsa = "EMSA1(SHA-384)";
} else if (type_str.find("SHA512") != std::string::npos) {
- kdf = "EMSA1(SHA-512)";
+ emsa = "EMSA1(SHA-512)";
}
- Botan::PK_Verifier verifier(*pkey, kdf, Botan::DER_SEQUENCE);
+ Botan::PK_Verifier verifier(*pkey, emsa, Botan::DER_SEQUENCE);
jsize data_length = env->GetArrayLength(data);
jsize sig_length = env->GetArrayLength(signature);
@@ -515,7 +513,9 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
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);
@@ -528,4 +528,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
return JNI_TRUE;
}
return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_supportsNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getNativeTimingResolution(JNIEnv *env, jobject self) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getLastNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_last();
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c
new file mode 100644
index 0000000..be46398
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c
@@ -0,0 +1,57 @@
+#include "c_timing.h"
+#include <time.h>
+
+#if _POSIX_TIMERS > 0
+
+struct timespec start = {0};
+struct timespec end = {0};
+
+jboolean native_timing_supported() {
+ return JNI_TRUE;
+}
+
+jlong native_timing_resolution() {
+ struct timespec timeval;
+ clock_getres(CLOCK_MONOTONIC, &timeval);
+ return timeval.tv_nsec;
+}
+
+
+void native_timing_start() {
+ clock_gettime(CLOCK_MONOTONIC, &start);
+}
+
+
+void native_timing_stop() {
+ clock_gettime(CLOCK_MONOTONIC, &end);
+}
+
+
+jlong native_timing_last() {
+ jlong res = (end.tv_sec - start.tv_sec) * 1000000000 + (end.tv_nsec - start.tv_nsec);
+ if (res < 0) {
+ return 0;
+ } else {
+ return res;
+ }
+}
+
+#else
+
+jboolean native_timing_supported() {
+ return JNI_FALSE;
+}
+
+jlong native_timing_resolution() {
+ return 0;
+}
+
+void native_timing_start() {}
+
+void native_timing_stop() {}
+
+jlong native_timing_last() {
+ return 0;
+}
+
+#endif \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h
new file mode 100644
index 0000000..bce2a19
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <jni.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ *
+ */
+jboolean native_timing_supported();
+
+/**
+ *
+ */
+jlong native_timing_resolution();
+
+/**
+ *
+ */
+void native_timing_start();
+
+/**
+ *
+ */
+void native_timing_stop();
+
+/**
+ *
+ */
+jlong native_timing_last();
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
index 49cab44..81d1fb8 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
@@ -75,7 +75,7 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...) {
char buffer[2048];
va_list args;
va_start(args, format);
- int res = vsnprintf(buffer, 2048, format, args);
+ vsnprintf(buffer, 2048, format, args);
va_end(args);
throw_new(env, class, buffer);
}
@@ -105,4 +105,109 @@ jint get_kdf_bits(JNIEnv *env, jstring algorithm) {
}
(*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) {
+ 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;
+ while ((s = s >> 8)) {
+ seq_len_len++;
+ }
+ }
+ // 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 << (seq_len_len - j)));
+ }
+ }
+ 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;
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
index b767b61..82c3538 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
@@ -1,6 +1,7 @@
#pragma once
#include "native.h"
+#include <stdbool.h>
/**
* Classes that are accessed alot are cached here, manually.
@@ -39,6 +40,16 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...);
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);
+
+/**
* 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;")
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
index 32121c5..089724e 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
+++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
@@ -23,7 +23,6 @@ using CryptoPP::byte;
#include "cryptopp/osrng.h"
using CryptoPP::AutoSeededRandomPool;
-using CryptoPP::AutoSeededX917RNG;
#include "cryptopp/sha.h"
using CryptoPP::SHA1;
@@ -71,8 +70,10 @@ 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) {
@@ -89,7 +90,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_crea
std::stringstream ss;
ss << lib_name << " ";
ss << info_str[0];
- for (int i = 1; i < info_str.size(); ++i) {
+ for (size_t i = 1; i < info_str.size(); ++i) {
ss << "." << info_str[i];
}
@@ -470,6 +471,8 @@ template <> jobject params_from_group<EC2N>(JNIEnv *env, DL_GroupParameters_EC<E
//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) {
@@ -492,12 +495,13 @@ template <> jobject params_from_group<EC2N>(JNIEnv *env, DL_GroupParameters_EC<E
}
template <class EC> jobject generate_from_group(JNIEnv *env, DL_GroupParameters_EC<EC> group, jobject params) {
- AutoSeededRandomPool rng;
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;
@@ -578,7 +582,9 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
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;
@@ -588,12 +594,18 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
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);
@@ -610,7 +622,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgr
template <class EC, class H>
jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray data, const Integer & private_key_x) {
- AutoSeededRandomPool prng;
typename ECDSA<EC, H>::PrivateKey pkey;
pkey.Initialize(group, private_key_x);
@@ -620,7 +631,9 @@ jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray
jsize data_length = env->GetArrayLength(data);
jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
- size_t len = signer.SignMessage(prng, (byte *)data_bytes, data_length, (byte *)signature.c_str());
+ 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);
@@ -648,7 +661,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
Integer private_key_x((byte *) privkey_data, (size_t) privkey_length);
env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
- jbyteArray result;
+ jbyteArray result = NULL;
std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
if (ecp_group == nullptr) {
@@ -705,7 +718,9 @@ jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray
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;
@@ -750,3 +765,15 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
// unreachable
return JNI_FALSE;
}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_supportsNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getNativeTimingResolution(JNIEnv *env, jobject self) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getLastNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
new file mode 100644
index 0000000..359d0f4
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
@@ -0,0 +1,635 @@
+#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;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c
index 5820afd..568e924 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c
@@ -1211,4 +1211,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptVerifySignature\n", status);
return JNI_FALSE;
}
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_supportsNativeTiming(JNIEnv *env, jobject self) {
+ return JNI_FALSE;
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getNativeTimingResolution(JNIEnv *env, jobject self) {
+ return 0;
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getLastNativeTiming(JNIEnv *env, jobject self) {
+ return 0;
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h
index e3bf3d8..e410204 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/native.h
+++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h
@@ -9,6 +9,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -190,6 +214,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -371,6 +419,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -552,6 +624,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -733,6 +829,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -905,3 +1025,413 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
}
#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: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * 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: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * 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
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c
index 255834a..a63c2fb 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c
@@ -1,6 +1,5 @@
#include "native.h"
#include <string.h>
-#include <stdio.h>
#include <openssl/conf.h>
#include <openssl/opensslv.h>
@@ -13,6 +12,8 @@
#include <openssl/ecdsa.h>
#include "c_utils.h"
+#include "c_timing.h"
+
static jclass provider_class;
@@ -88,7 +89,7 @@ static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) {
int size = BN_num_bytes(bn);
jbyteArray bytes = (*env)->NewByteArray(env, size);
jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
- BN_bn2bin(bn, data);
+ 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;
@@ -100,7 +101,7 @@ static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) {
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(byte_data, byte_length, NULL);
+ BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL);
(*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
return result;
}
@@ -112,10 +113,6 @@ static EC_GROUP *create_curve(JNIEnv *env, jobject params) {
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);
BIGNUM *a_bn = biginteger_to_bignum(env, a);
@@ -286,7 +283,7 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
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, &ks_data[0])) {
+ 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);
@@ -295,7 +292,7 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
} 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, &ks_data[0], &ks_data[1], &ks_data[2])) {
+ 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);
@@ -327,7 +324,6 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
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);
- fflush(stderr);
BN_free(a);
BN_free(b);
@@ -354,7 +350,12 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
EC_KEY *key = EC_KEY_new();
EC_KEY_set_group(key, curve);
- if (!EC_KEY_generate_key(key)) {
+
+ 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;
@@ -362,13 +363,13 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
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), key_priv, key_bytes);
+ 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, key_pub, key_len, 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);
@@ -377,7 +378,7 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *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_param_spec);
+ 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");
@@ -424,7 +425,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai
size_t ncurves = EC_get_builtin_curves(NULL, 0);
EC_builtin_curve curves[ncurves];
EC_get_builtin_curves(curves, ncurves);
- EC_GROUP *curve;
+ 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);
@@ -451,7 +452,7 @@ EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) {
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, pub_data, pub_len, NULL);
+ 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);
@@ -463,7 +464,7 @@ EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv)
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(priv_data, priv_len, 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);
@@ -487,7 +488,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
// 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);
- if (ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL) <= 0) {
+
+ 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);
@@ -518,7 +524,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
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?
- ECDSA_SIG *signature = ECDSA_do_sign(data_data, data_size, priv);
+
+ 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.");
@@ -556,7 +566,11 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
jsize data_size = (*env)->GetArrayLength(env, data);
jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
- int result = ECDSA_do_verify(data_data, data_size, sig_obj, pub);
+
+ 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);
@@ -570,3 +584,15 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
EC_GROUP_free(curve);
return (result == 1) ? JNI_TRUE : JNI_FALSE;
}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
index fdf5663..471190e 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <tomcrypt.h>
#include "c_utils.h"
+#include "c_timing.h"
static prng_state ltc_prng;
static jclass provider_class;
@@ -20,7 +21,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_crea
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;
@@ -243,26 +243,30 @@ static void free_curve(ltc_ecc_set_type *curve) {
static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) {
ecc_key key;
- int err;
- if ((err = ecc_make_key_ex(&ltc_prng, find_prng("yarrow"), &key, curve)) != CRYPT_OK) {
+
+ native_timing_start();
+ int err = ecc_make_key_ex(&ltc_prng, find_prng("yarrow"), &key, curve);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
return NULL;
}
unsigned long key_len = 2*curve->size + 1;
jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
- ecc_ansi_x963_export(&key, key_pub, &key_len);
+ 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_param_spec);
+ 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, key_priv);
+ 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);
@@ -334,7 +338,7 @@ static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ec
out->idx = -1;
out->dp = curve;
ltc_mp.init(&out->k);
- ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size);
+ 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;
@@ -355,8 +359,8 @@ static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_
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, pub_data + 1, (unsigned long) curve->size);
- ltc_mp.unsigned_read(out->pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size);
+ 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);
@@ -380,8 +384,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
unsigned char result[curve->size];
unsigned long output_len = curve->size;
- int err;
- if ((err = ecc_shared_secret(&priv, &pub, result, &output_len)) != CRYPT_OK) {
+
+ 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;
@@ -416,8 +424,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
unsigned char result[curve->size*4];
unsigned long output_len = curve->size*4;
- int err;
- if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, &ltc_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) {
+
+ native_timing_start();
+ int err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, &ltc_prng, find_prng("yarrow"), &priv);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
free_curve(curve);
(*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
@@ -450,9 +462,12 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
jsize sig_size = (*env)->GetArrayLength(env, signature);
jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
- int err;
int result;
- if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) {
+ 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);
@@ -464,4 +479,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
(*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
free_curve(curve);
return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
index bf9ec7d..d7be4dc 100644
--- a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
+++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
@@ -33,10 +33,11 @@ public class TextTestWriter extends BaseTextTestWriter {
protected String testableString(Testable t) {
if (t instanceof StandaloneTestable) {
StandaloneTestable<?> testable = (StandaloneTestable) t;
- String stage = testable.getStage().name();
+ Enum<?> stage = testable.getStage();
+ String stageName = stage.name();
String exception = causeString(testable.getException());
String errorCause = causeString(testable.errorCause());
- return stage + exception + errorCause;
+ return String.format("[%d/%d] %s %s %s", stage.ordinal() + 1, stage.getClass().getEnumConstants().length, stageName, exception, errorCause);
}
return "";
}