diff options
| author | J08nY | 2018-11-28 01:04:31 +0100 |
|---|---|---|
| committer | J08nY | 2018-11-28 01:04:31 +0100 |
| commit | ebe40e2fdd5e28cdabe05250422f3149e188641a (patch) | |
| tree | fbf29423e8053c6a7267d600d1630fefb1bf1a1b /src/cz/crcs/ectester/standalone | |
| parent | 7e9917742785a9fd532a52231e95ddad5775555f (diff) | |
| parent | 12845c8c41eff5f598dc8e843920f5bb4638775d (diff) | |
| download | ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.gz ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.zst ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.zip | |
Merge branch 'devel'
Diffstat (limited to 'src/cz/crcs/ectester/standalone')
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(<c_prng, find_prng("yarrow"), &key, curve)) != CRYPT_OK) { + + native_timing_start(); + int err = ecc_make_key_ex(<c_prng, find_prng("yarrow"), &key, curve); + native_timing_stop(); + + if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); return NULL; } unsigned long key_len = 2*curve->size + 1; jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len); jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL); - ecc_ansi_x963_export(&key, 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, <c_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) { + + native_timing_start(); + int err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv); + native_timing_stop(); + + if (err != CRYPT_OK) { throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); free_curve(curve); (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); @@ -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 ""; } |
