diff options
| author | J08nY | 2018-01-23 17:31:15 +0100 |
|---|---|---|
| committer | J08nY | 2018-01-23 17:31:15 +0100 |
| commit | cb6c6b8b1274fe5a340c4317a4b015ea0ef15396 (patch) | |
| tree | 864a54dcdf07da33cd139312c8b0ee693e1a0eff /src/cz/crcs/ectester/standalone/libs | |
| parent | 6c46a27a52854aee24f7a37e74002bd6f4485723 (diff) | |
| parent | c581e39e539e6dadb49d9f83f563ab2b375f6e0b (diff) | |
| download | ECTester-0.2.0.tar.gz ECTester-0.2.0.tar.zst ECTester-0.2.0.zip | |
Diffstat (limited to 'src/cz/crcs/ectester/standalone/libs')
21 files changed, 2677 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/standalone/libs/BotanLib.java b/src/cz/crcs/ectester/standalone/libs/BotanLib.java new file mode 100644 index 0000000..cd28791 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/BotanLib.java @@ -0,0 +1,20 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class BotanLib extends NativeECLibrary { + + public BotanLib() { + super("botan_provider", "botan-2"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set<String> getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java new file mode 100644 index 0000000..c6600f9 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java @@ -0,0 +1,28 @@ +package cz.crcs.ectester.standalone.libs; + +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.util.Enumeration; +import java.util.Set; +import java.util.TreeSet; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class BouncyCastleLib extends ProviderECLibrary { + + public BouncyCastleLib() { + super(new BouncyCastleProvider()); + } + + @Override + public Set<String> getCurves() { + Set<String> result = new TreeSet<>(); + Enumeration names = ECNamedCurveTable.getNames(); + while (names.hasMoreElements()) { + result.add((String) names.nextElement()); + } + return result; + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/ECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java new file mode 100644 index 0000000..0f81978 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java @@ -0,0 +1,26 @@ +package cz.crcs.ectester.standalone.libs; + +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; + +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public interface ECLibrary { + boolean initialize(); + + boolean isInitialized(); + + Set<String> getCurves(); + + Set<KeyAgreementIdent> getKAs(); + + Set<SignatureIdent> getSigs(); + + Set<KeyPairGeneratorIdent> getKPGs(); + + String name(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java new file mode 100644 index 0000000..0a420a1 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java @@ -0,0 +1,119 @@ +package cz.crcs.ectester.standalone.libs; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.security.Provider; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeECLibrary extends ProviderECLibrary { + private String resource; + private String[] requriements; + + public static String LIB_RESOURCE_DIR = "/cz/crcs/ectester/standalone/libs/jni/"; + + public NativeECLibrary(String resource, String... requirements) { + this.resource = resource; + this.requriements = requirements; + } + + @Override + public boolean initialize() { + try { + /* Determine what OS are we running on and use appropriate suffix and path. */ + String suffix; + Path appData; + if (System.getProperty("os.name").startsWith("Windows")) { + suffix = "dll"; + appData = Paths.get(System.getenv("AppData")); + } else { + suffix = "so"; + if (System.getProperty("os.name").startsWith("Linux")) { + String dataHome = System.getenv("XDG_DATA_HOME"); + if (dataHome != null) { + appData = Paths.get(dataHome); + } else { + appData = Paths.get(System.getProperty("user.home"), ".local", "share"); + } + } else { + appData = Paths.get(System.getProperty("user.home"), ".local", "share"); + } + } + Path libDir = appData.resolve("ECTesterStandalone"); + File libDirFile = libDir.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(); + + 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(); + + /* + * Need to hack in /usr/local/lib to path. + * See: https://stackoverflow.com/questions/5419039/is-djava-library-path-equivalent-to-system-setpropertyjava-library-path/24988095#24988095 + */ + String path = System.getProperty("java.library.path"); + if (suffix.equals("so")) { + String newPath = path + ":/usr/local/lib"; + System.setProperty("java.library.path", newPath); + Field fieldSysPath; + try { + fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" ); + fieldSysPath.setAccessible( true ); + fieldSysPath.set( null, null ); + } catch (NoSuchFieldException | IllegalAccessException ignored) { + } + } + + for (String requirement : requriements) { + System.loadLibrary(requirement); + } + + if (suffix.equals("so")) { + System.setProperty("java.library.path", path); + } + + System.load(libPath.toString()); + + provider = createProvider(); + return super.initialize(); + } catch (IOException | UnsatisfiedLinkError ignored) { + } + return false; + } + + abstract Provider createProvider(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java new file mode 100644 index 0000000..9108eaf --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java @@ -0,0 +1,93 @@ +package cz.crcs.ectester.standalone.libs; + +import cz.crcs.ectester.standalone.consts.Ident; +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; + +import java.security.Provider; +import java.security.Security; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class ProviderECLibrary implements ECLibrary { + Provider provider; + private boolean initialized = false; + + public ProviderECLibrary() { + + } + + public ProviderECLibrary(Provider provider) { + this.provider = provider; + } + + @Override + public boolean initialize() { + try { + int result = Security.addProvider(provider); + if (result == -1) { + provider = Security.getProvider(provider.getName()); + } + initialized = true; + } catch (NullPointerException | SecurityException ignored) { + initialized = false; + } + return initialized; + } + + @Override + public boolean isInitialized() { + return initialized; + } + + private <T extends Ident> Set<T> getIdents(String type, Function<String, T> getter) { + Set<T> results = new HashSet<>(); + if (!initialized) { + return results; + } + + for (Provider.Service service : provider.getServices()) { + if (service.getType().equals(type)) { + T id = getter.apply(service.getAlgorithm()); + if (id != null) { + results.add(id); + } + } + } + return results; + } + + @Override + public Set<KeyAgreementIdent> getKAs() { + return getIdents("KeyAgreement", KeyAgreementIdent::get); + } + + @Override + public Set<SignatureIdent> getSigs() { + return getIdents("Signature", SignatureIdent::get); + } + + @Override + public Set<KeyPairGeneratorIdent> getKPGs() { + return getIdents("KeyPairGenerator", KeyPairGeneratorIdent::get); + } + + @Override + public String name() { + return provider.getInfo(); + } + + public Provider getProvider() { + return provider; + } + + @Override + public String toString() { + return name(); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/SunECLib.java b/src/cz/crcs/ectester/standalone/libs/SunECLib.java new file mode 100644 index 0000000..3aec842 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/SunECLib.java @@ -0,0 +1,28 @@ +package cz.crcs.ectester.standalone.libs; + +import sun.security.ec.SunEC; + +import java.util.Set; +import java.util.TreeSet; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SunECLib extends ProviderECLibrary { + + public SunECLib() { + super(new SunEC()); + } + + @Override + public Set<String> getCurves() { + String curves = provider.get("AlgorithmParameters.EC SupportedCurves").toString(); + String[] split = curves.split("\\|"); + Set<String> result = new TreeSet<>(); + for (String curve : split) { + String body = curve.split(",")[0].substring(1); + result.add(body); + } + return result; + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java new file mode 100644 index 0000000..57b273a --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java @@ -0,0 +1,20 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TomcryptLib extends NativeECLibrary { + + public TomcryptLib() { + super("tomcrypt_provider", "tommath", "tomcrypt"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set<String> getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile new file mode 100644 index 0000000..3530499 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -0,0 +1,70 @@ +ifeq ($(JAVA_HOME),) +ifeq ($(OS),Windows_NT) +which = $(shell where $1) +else +which = $(shell which $1) +endif +JAVAC ?= $(realpath $(call which,javac)) +JAVA_HOME = $(abspath $(dir $(JAVAC))..) +endif + +ifneq ($(JAVA_HOME),) +JNI_INCLUDEDIR ?= $(JAVA_HOME)/include +endif + +ifeq ($(JNI_INCLUDEDIR),) +$(error could not determine JNI include dir, try specifying either \ + JAVA_HOME or JNI_INCLUDEDIR) +endif + +TARGETTRIPLET := $(shell $(CC) -dumpmachine) +ifeq ($(JNI_PLATFORM),) +ifeq ($(findstring mingw,$(TARGETTRIPLET)),mingw) +JNI_PLATFORM:= win32 +else +ifeq ($(findstring linux,$(TARGETTRIPLET)),linux) +JNI_PLATFORM:= linux +# 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++ + +CFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. +CXXFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. + + +all: tomcrypt_provider.so botan_provider.so + +c_utils.o: c_utils.c + $(CC) $(CFLAGS) -c $< + +cpp_utils.o: cpp_utils.cpp + $(CXX) $(CXXFLAGS) -c $< + + +tomcrypt_provider.so: tomcrypt.o c_utils.o + $(CC) -fPIC -g -shared -o $@ $^ -L. -ltommath -ltomcrypt + +tomcrypt.o: tomcrypt.c + $(CC) -DLTM_DESC $(CFLAGS) -c $< + + +botan_provider.so: botan.o cpp_utils.o + $(CXX) -fPIC -g -shared -o $@ $^ -L. -L"$(LOCAL_LIBS)" -lbotan-2 -fstack-protector -m64 -pthread + +botan.o: botan.cpp + $(CXX) -I"$(LOCAL_INCLUDES)/botan-2" $(CFLAGS) -c $< + +clean: + rm -rf *.o + rm -rf *.so + +.PHONY: all 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 new file mode 100644 index 0000000..22e5329 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -0,0 +1,68 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import org.bouncycastle.util.Arrays; + +import java.math.BigInteger; +import java.security.interfaces.ECPrivateKey; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeECPrivateKey implements ECPrivateKey { + private String algorithm; + private String format; + + public NativeECPrivateKey(String algorithm, String format) { + this.algorithm = algorithm; + this.format = format; + } + + @Override + public String getAlgorithm() { + return algorithm; + } + + @Override + public String getFormat() { + return format; + } + + private static class Raw extends NativeECPrivateKey { + private byte[] keyData; + private ECParameterSpec params; + + public Raw(byte[] keyData, ECParameterSpec params) { + super("EC", "raw"); + this.keyData = keyData; + this.params = params; + } + + @Override + public BigInteger getS() { + return new BigInteger(1, keyData); + } + + @Override + public byte[] getEncoded() { + return Arrays.clone(keyData); + } + + @Override + public ECParameterSpec getParams() { + return params; + } + } + + public static class TomCrypt extends Raw { + public TomCrypt(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + + public static class Botan extends Raw { + public Botan(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java new file mode 100644 index 0000000..8fc4747 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -0,0 +1,69 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import cz.crcs.ectester.common.util.ECUtil; +import org.bouncycastle.util.Arrays; + +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeECPublicKey implements ECPublicKey { + private String algorithm; + private String format; + + public NativeECPublicKey(String algorithm, String format) { + this.algorithm = algorithm; + this.format = format; + } + + @Override + public String getAlgorithm() { + return algorithm; + } + + @Override + public String getFormat() { + return format; + } + + private static class ANSIX962 extends NativeECPublicKey { + private byte[] keyData; + private ECParameterSpec params; + + public ANSIX962(byte[] keyData, ECParameterSpec params) { + super("EC", "ANSI X9.62"); + this.keyData = keyData; + this.params = params; + } + + @Override + public ECPoint getW() { + return ECUtil.fromX962(keyData, params.getCurve()); + } + + @Override + public byte[] getEncoded() { + return Arrays.clone(keyData); + } + + @Override + public ECParameterSpec getParams() { + return params; + } + } + + public static class TomCrypt extends ANSIX962 { + public TomCrypt(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + + public static class Botan extends ANSIX962 { + public Botan(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java new file mode 100644 index 0000000..37c9add --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -0,0 +1,137 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import cz.crcs.ectester.common.util.ECUtil; + +import javax.crypto.KeyAgreementSpi; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { + private ECPrivateKey privateKey; + private ECPublicKey publicKey; + private ECParameterSpec params; + + @Override + protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { + if (!(key instanceof ECPrivateKey)) { + throw new InvalidKeyException + ("Key must be instance of ECPrivateKey"); + } + privateKey = (ECPrivateKey) key; + this.params = privateKey.getParams(); + } + + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(params instanceof ECParameterSpec)) { + throw new InvalidAlgorithmParameterException(); + } + engineInit(key, random); + this.params = (ECParameterSpec) params; + } + + @Override + protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException { + if (privateKey == null) { + throw new IllegalStateException("Not initialized"); + } + if (publicKey != null) { + throw new IllegalStateException("Phase already executed"); + } + if (!lastPhase) { + throw new IllegalStateException + ("Only two party agreement supported, lastPhase must be true"); + } + if (!(key instanceof ECPublicKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPublicKey"); + } + publicKey = (ECPublicKey) key; + return null; + } + + @Override + protected byte[] engineGenerateSecret() throws IllegalStateException { + byte[] pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve()); + byte[] privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize()); + return generateSecret(pubkey, privkey, params); + } + + @Override + protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException { + byte[] secret = engineGenerateSecret(); + if (sharedSecret.length < offset + secret.length) { + throw new ShortBufferException(); + } + System.arraycopy(secret, 0, sharedSecret, offset, secret.length); + return secret.length; + } + + @Override + protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { + throw new NoSuchAlgorithmException(algorithm); + } + + abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + + + public static class TomCrypt extends NativeKeyAgreementSpi { + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + } + + public abstract static class Botan extends NativeKeyAgreementSpi { + private String type; + public Botan(String type) { + this.type = type; + } + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + } + + public static class BotanECDH extends Botan { + public BotanECDH() { + super("ECDH"); + } + } + + public static class BotanECDHwithSHA1KDF extends Botan { + public BotanECDHwithSHA1KDF() { + super("ECDHwithSHA1KDF"); + } + } + + public static class BotanECDHwithSHA224KDF extends Botan { + public BotanECDHwithSHA224KDF() { + super("ECDHwithSHA224KDF"); + } + } + + public static class BotanECDHwithSHA256KDF extends Botan { + public BotanECDHwithSHA256KDF() { + super("ECDHwithSHA256KDF"); + } + } + + public static class BotanECDHwithSHA384KDF extends Botan { + public BotanECDHwithSHA384KDF() { + super("ECDHwithSHA384KDF"); + } + } + + public static class BotanECDHwithSHA512KDF extends Botan { + public BotanECDHwithSHA512KDF() { + super("ECDHwithSHA512KDF"); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java new file mode 100644 index 0000000..9461251 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -0,0 +1,123 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { + private int keysize; + private SecureRandom random; + private AlgorithmParameterSpec params; + private boolean useKeysize; + private boolean useParams; + + @Override + public void initialize(int keysize, SecureRandom random) { + if (!keysizeSupported(keysize)) { + throw new InvalidParameterException("Keysize " + keysize + " not supported."); + } + this.keysize = keysize; + this.random = random; + this.useKeysize = true; + this.useParams = false; + } + + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { + if (!paramsSupported(params)) { + throw new InvalidAlgorithmParameterException("not supported."); + } + this.params = params; + this.random = random; + this.useParams = true; + this.useKeysize = false; + } + + @Override + public KeyPair generateKeyPair() { + if (useKeysize) { + return generate(keysize, random); + } else if (useParams) { + return generate(params, random); + } + return null; + } + + abstract boolean keysizeSupported(int keysize); + + abstract boolean paramsSupported(AlgorithmParameterSpec params); + + abstract KeyPair generate(int keysize, SecureRandom random); + + abstract KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + + public static class TomCrypt extends NativeKeyPairGeneratorSpi { + + public TomCrypt() { + 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 abstract class Botan extends NativeKeyPairGeneratorSpi { + private String type; + + public Botan(String type) { + this.type = type; + 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 BotanECDH extends Botan { + + public BotanECDH() { + super("ECDH"); + } + } + + public static class BotanECDSA extends Botan { + + public BotanECDSA() { + super("ECDSA"); + } + } + + public static class BotanECKCDSA extends Botan { + + public BotanECKCDSA() { + super("ECKCDSA"); + } + } + + public static class BotanECGDSA extends Botan { + + public BotanECGDSA() { + super("ECGDSA"); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java new file mode 100644 index 0000000..a0689d6 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java @@ -0,0 +1,42 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeProvider extends Provider { + + public NativeProvider(String name, double version, String info) { + super(name, version, info); + + AccessController.doPrivileged((PrivilegedAction<Object>) () -> { + setup(); + return null; + }); + } + + abstract void setup(); + + public static class TomCrypt extends NativeProvider { + + public TomCrypt(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } + + public static class Botan extends NativeProvider { + + public Botan(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java new file mode 100644 index 0000000..b212697 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java @@ -0,0 +1,227 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import cz.crcs.ectester.common.util.ECUtil; + +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeSignatureSpi extends SignatureSpi { + private ECPublicKey verifyKey; + private ECPrivateKey signKey; + private ECParameterSpec params; + + private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + if (!(publicKey instanceof ECPublicKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPublicKey"); + } + verifyKey = (ECPublicKey) publicKey; + params = verifyKey.getParams(); + buffer.reset(); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + if (!(privateKey instanceof ECPrivateKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPrivateKey"); + } + signKey = (ECPrivateKey) privateKey; + params = signKey.getParams(); + buffer.reset(); + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { + buffer.write(b); + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { + buffer.write(b, off, len); + } + + @Override + protected byte[] engineSign() throws SignatureException { + return sign(buffer.toByteArray(), ECUtil.toByteArray(signKey.getS(), params.getCurve().getField().getFieldSize()), params); + } + + @Override + protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + return verify(sigBytes, buffer.toByteArray(), ECUtil.toX962Uncompressed(verifyKey.getW(), params), params); + } + + @Override + @Deprecated + protected void engineSetParameter(String param, Object value) throws InvalidParameterException { + throw new UnsupportedOperationException("setParameter() not supported"); + } + + @Override + @Deprecated + protected Object engineGetParameter(String param) throws InvalidParameterException { + throw new UnsupportedOperationException("getParameter() not supported"); + } + + abstract byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + abstract boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + + public static class TomCryptRaw extends NativeSignatureSpi { + + @Override + native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + @Override + native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + } + + public abstract static class Botan extends NativeSignatureSpi { + private String type; + + public Botan(String type) { + this.type = type; + } + + @Override + native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + @Override + native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + } + + public static class BotanECDSAwithNONE extends Botan { + + public BotanECDSAwithNONE() { + super("NONEwithECDSA"); + } + } + + public static class BotanECDSAwithSHA1 extends Botan { + + public BotanECDSAwithSHA1() { + super("SHA1withECDSA"); + } + } + + public static class BotanECDSAwithSHA224 extends Botan { + + public BotanECDSAwithSHA224() { + super("SHA224withECDSA"); + } + } + + public static class BotanECDSAwithSHA256 extends Botan { + + public BotanECDSAwithSHA256() { + super("SHA256withECDSA"); + } + } + + public static class BotanECDSAwithSHA384 extends Botan { + + public BotanECDSAwithSHA384() { + super("SHA384withECDSA"); + } + } + + public static class BotanECDSAwithSHA512 extends Botan { + + public BotanECDSAwithSHA512() { + super("SHA512withECDSA"); + } + } + + public static class BotanECKCDSAwithNONE extends Botan { + + public BotanECKCDSAwithNONE() { + super("NONEwithECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA1 extends Botan { + + public BotanECKCDSAwithSHA1() { + super("SHA1withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA224 extends Botan { + + public BotanECKCDSAwithSHA224() { + super("SHA224withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA256 extends Botan { + + public BotanECKCDSAwithSHA256() { + super("SHA256withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA384 extends Botan { + + public BotanECKCDSAwithSHA384() { + super("SHA384withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA512 extends Botan { + + public BotanECKCDSAwithSHA512() { + super("SHA512withECKCDSA"); + } + } + + public static class BotanECGDSAwithNONE extends Botan { + + public BotanECGDSAwithNONE() { + super("NONEwithECGDSA"); + } + } + + public static class BotanECGDSAwithSHA1 extends Botan { + + public BotanECGDSAwithSHA1() { + super("SHA1withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA224 extends Botan { + + public BotanECGDSAwithSHA224() { + super("SHA224withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA256 extends Botan { + + public BotanECGDSAwithSHA256() { + super("SHA256withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA384 extends Botan { + + public BotanECGDSAwithSHA384() { + super("SHA384withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA512 extends Botan { + + public BotanECGDSAwithSHA512() { + super("SHA512withECGDSA"); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp new file mode 100644 index 0000000..8e666d6 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp @@ -0,0 +1,631 @@ +#include "native.h" +#include <string> +#include <botan/botan.h> +#include <botan/ec_group.h> +#include <botan/ecc_key.h> +#include <botan/ecdsa.h> +#include <botan/eckcdsa.h> +#include <botan/ecgdsa.h> +#include <botan/ecdh.h> +#include <botan/pubkey.h> +#include "cpp_utils.hpp" + +static jclass provider_class; + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider(JNIEnv *env, jobject self) { + /* Create the custom provider. */ + jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Botan"); + provider_class = (jclass) env->NewGlobalRef(local_provider_class); + + jmethodID init = env->GetMethodID(local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V"); + + const char* info_str = Botan::version_cstr(); + const char* v_str = Botan::short_version_cstr(); + std::string name_str = Botan::short_version_string(); + name_str.insert(0, "Botan "); + + jstring name = env->NewStringUTF(name_str.c_str()); + double version = strtod(v_str, NULL); + jstring info = env->NewStringUTF(info_str); + + return env->NewObject(provider_class, init, name, version, info); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup(JNIEnv *env, jobject self){ + jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + jstring ecdh = env->NewStringUTF("KeyPairGenerator.ECDH"); + jstring ecdh_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDH"); + env->CallObjectMethod(self, provider_put, ecdh, ecdh_value); + + jstring ecdsa = env->NewStringUTF("KeyPairGenerator.ECDSA"); + jstring ecdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDSA"); + env->CallObjectMethod(self, provider_put, ecdsa, ecdsa_value); + + jstring eckcdsa = env->NewStringUTF("KeyPairGenerator.ECKCDSA"); + jstring eckcdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECKCDSA"); + env->CallObjectMethod(self, provider_put, eckcdsa, eckcdsa_value); + + jstring ecgdsa = env->NewStringUTF("KeyPairGenerator.ECGDSA"); + jstring ecgdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECGDSA"); + env->CallObjectMethod(self, provider_put, ecgdsa, ecgdsa_value); + + jstring ecdh_ka = env->NewStringUTF("KeyAgreement.ECDH"); + jstring ecdh_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDH"); + env->CallObjectMethod(self, provider_put, ecdh_ka, ecdh_ka_value); + + jstring ecdh_sha1_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA1KDF"); + jstring ecdh_sha1_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA1KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha1_ka, ecdh_sha1_ka_value); + + jstring ecdh_sha224_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA224KDF"); + jstring ecdh_sha224_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA224KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha224_ka, ecdh_sha224_ka_value); + + jstring ecdh_sha256_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA256KDF"); + jstring ecdh_sha256_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA256KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha256_ka, ecdh_sha256_ka_value); + + jstring ecdh_sha384_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA384KDF"); + jstring ecdh_sha384_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA384KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha384_ka, ecdh_sha384_ka_value); + + jstring ecdh_sha512_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA512KDF"); + jstring ecdh_sha512_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA512KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha512_ka, ecdh_sha512_ka_value); + + jstring ecdsa_sig = env->NewStringUTF("Signature.NONEwithECDSA"); + jstring ecdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithNONE"); + env->CallObjectMethod(self, provider_put, ecdsa_sig, ecdsa_sig_value); + + jstring ecdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECDSA"); + jstring ecdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA1"); + env->CallObjectMethod(self, provider_put, ecdsa_sha1_sig, ecdsa_sha1_sig_value); + + jstring ecdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECDSA"); + jstring ecdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA224"); + env->CallObjectMethod(self, provider_put, ecdsa_sha224_sig, ecdsa_sha224_sig_value); + + jstring ecdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECDSA"); + jstring ecdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA256"); + env->CallObjectMethod(self, provider_put, ecdsa_sha256_sig, ecdsa_sha256_sig_value); + + jstring ecdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECDSA"); + jstring ecdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA384"); + env->CallObjectMethod(self, provider_put, ecdsa_sha384_sig, ecdsa_sha384_sig_value); + + jstring ecdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECDSA"); + jstring ecdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA512"); + env->CallObjectMethod(self, provider_put, ecdsa_sha512_sig, ecdsa_sha512_sig_value); + + jstring eckcdsa_sig = env->NewStringUTF("Signature.NONEwithECKCDSA"); + jstring eckcdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithNONE"); + env->CallObjectMethod(self, provider_put, eckcdsa_sig, eckcdsa_sig_value); + + jstring eckcdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECKCDSA"); + jstring eckcdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA1"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha1_sig, eckcdsa_sha1_sig_value); + + jstring eckcdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECKCDSA"); + jstring eckcdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA224"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha224_sig, eckcdsa_sha224_sig_value); + + jstring eckcdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECKCDSA"); + jstring eckcdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA256"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha256_sig, eckcdsa_sha256_sig_value); + + jstring eckcdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECKCDSA"); + jstring eckcdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA384"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha384_sig, eckcdsa_sha384_sig_value); + + jstring eckcdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECKCDSA"); + jstring eckcdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA512"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha512_sig, eckcdsa_sha512_sig_value); + + jstring ecgdsa_sig = env->NewStringUTF("Signature.NONEwithECGDSA"); + jstring ecgdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithNONE"); + env->CallObjectMethod(self, provider_put, ecgdsa_sig, ecgdsa_sig_value); + + jstring ecgdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECGDSA"); + jstring ecgdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA1"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha1_sig, ecgdsa_sha1_sig_value); + + jstring ecgdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECGDSA"); + jstring ecgdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA224"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha224_sig, ecgdsa_sha224_sig_value); + + jstring ecgdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECGDSA"); + jstring ecgdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA256"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha256_sig, ecgdsa_sha256_sig_value); + + jstring ecgdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECGDSA"); + jstring ecgdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA384"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha384_sig, ecgdsa_sha384_sig_value); + + jstring ecgdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECGDSA"); + jstring ecgdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA512"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha512_sig, ecgdsa_sha512_sig_value); + + init_classes(env, "Botan"); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves(JNIEnv *env, jobject self){ + jclass hash_set_class = env->FindClass("java/util/TreeSet"); + + jmethodID hash_set_ctr = env->GetMethodID(hash_set_class, "<init>", "()V"); + jmethodID hash_set_add = env->GetMethodID(hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = env->NewObject(hash_set_class, hash_set_ctr); + + const std::set<std::string>& curves = Botan::EC_Group::known_named_groups(); + for (auto it = curves.begin(); it != curves.end(); ++it) { + std::string curve_name = *it; + jstring name_str = env->NewStringUTF(curve_name.c_str()); + env->CallBooleanMethod(result, hash_set_add, name_str); + } + + return result; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported(JNIEnv *env, jobject self, jint keysize){ + return JNI_TRUE; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported(JNIEnv *env, jobject self, jobject params){ + if (params == NULL) { + return JNI_FALSE; + } + + if (env->IsInstanceOf(params, ec_parameter_spec_class)) { + jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject curve = env->CallObjectMethod(params, get_curve); + + jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = env->CallObjectMethod(curve, get_field); + + if (env->IsInstanceOf(field, fp_field_class)) { + return JNI_TRUE; + } + } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) { + const std::set<std::string>& curves = Botan::EC_Group::known_named_groups(); + jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (jstring) env->CallObjectMethod(params, get_name); + const char *utf_name = env->GetStringUTFChars(name, NULL); + std::string str_name(utf_name); + env->ReleaseStringUTFChars(name, utf_name); + if (curves.find(str_name) != curves.end()) { + return JNI_TRUE; + } + } + return JNI_FALSE; +} + +static jobject biginteger_from_bigint(JNIEnv *env, const Botan::BigInt& bigint) { + std::vector<uint8_t> bigint_data = Botan::BigInt::encode(bigint); + jbyteArray bigint_array = env->NewByteArray(bigint_data.size()); + jbyte * bigint_bytes = env->GetByteArrayElements(bigint_array, NULL); + std::copy(bigint_data.begin(), bigint_data.end(), bigint_bytes); + env->ReleaseByteArrayElements(bigint_array, bigint_bytes, JNI_COMMIT); + + jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V"); + return env->NewObject(biginteger_class, biginteger_init, (jint) 1, bigint_array); +} + +static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) { + jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B"); + jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(biginteger, to_byte_array); + jsize byte_length = env->GetArrayLength(byte_array); + jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL); + Botan::BigInt result((unsigned uint8_t*) byte_data, byte_length); + env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT); + return result; +} + +static Botan::EC_Group group_from_params(JNIEnv *env, jobject params) { + if (env->IsInstanceOf(params, ec_parameter_spec_class)) { + jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = env->CallObjectMethod(params, get_curve); + + jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = env->CallObjectMethod(elliptic_curve, get_field); + + jmethodID get_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); + + jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = env->CallObjectMethod(elliptic_curve, get_b); + + jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = env->CallObjectMethod(field, get_p); + + jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = env->CallObjectMethod(params, get_g); + + jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = env->CallObjectMethod(g, get_x); + + jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = env->CallObjectMethod(g, get_y); + + jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = env->CallObjectMethod(params, get_n); + + jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I"); + jint h = env->CallIntMethod(params, get_h); + + Botan::BigInt pi = bigint_from_biginteger(env, p); + Botan::BigInt ai = bigint_from_biginteger(env, a); + Botan::BigInt bi = bigint_from_biginteger(env, b); + Botan::CurveGFp curve(pi, ai, bi); + + Botan::BigInt gxi = bigint_from_biginteger(env, gx); + Botan::BigInt gyi = bigint_from_biginteger(env, gy); + Botan::PointGFp generator(curve, gxi, gyi); + + Botan::BigInt ni = bigint_from_biginteger(env, n); + Botan::BigInt hi(h); + + return Botan::EC_Group(curve, generator, ni, hi); + } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) { + jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (jstring) env->CallObjectMethod(params, get_name); + const char *utf_name = env->GetStringUTFChars(name, NULL); + std::string curve_name(utf_name); + env->ReleaseStringUTFChars(name, utf_name); + return Botan::EC_Group(curve_name); + } + return Botan::EC_Group(); +} + +static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) { + const Botan::CurveGFp& curve = group.get_curve(); + jobject p = biginteger_from_bigint(env, curve.get_p()); + + jmethodID fp_field_init = env->GetMethodID(fp_field_class, "<init>", "(Ljava/math/BigInteger;)V"); + jobject fp_field = env->NewObject(fp_field_class, fp_field_init, p); + + jobject a = biginteger_from_bigint(env, curve.get_a()); + jobject b = biginteger_from_bigint(env, curve.get_b()); + + jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, fp_field, a, b); + + const Botan::PointGFp& generator = group.get_base_point(); + jobject gx = biginteger_from_bigint(env, generator.get_affine_x()); + jobject gy = biginteger_from_bigint(env, generator.get_affine_y()); + + jmethodID point_init = env->GetMethodID(point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = env->NewObject(point_class, point_init, gx, gy); + + const Botan::BigInt& order = group.get_order(); + jobject n = biginteger_from_bigint(env, order); + + const Botan::BigInt& cofactor = group.get_cofactor(); + jint h = (jint) cofactor.to_u32bit(); + + jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); + return env->NewObject(ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, h); +} + +static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) { + 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); + const char* type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + std::unique_ptr<Botan::EC_PrivateKey> skey; + try { + if (type_str == "ECDH") { + skey = std::make_unique<Botan::ECDH_PrivateKey>(rng, group); + } else if (type_str == "ECDSA") { + skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, group); + } else if (type_str == "ECKCDSA") { + skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, group); + } else if (type_str == "ECGDSA") { + skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, group); + } + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + return NULL; + } + + jobject ec_param_spec = params_from_group(env, group); + + const Botan::PointGFp& pub_point = skey->public_point(); + std::vector<uint8_t> pub_data = Botan::unlock(Botan::EC2OSP(pub_point, Botan::PointGFp::UNCOMPRESSED)); + + jbyteArray pub_bytearray = env->NewByteArray(pub_data.size()); + jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL); + std::copy(pub_data.begin(), pub_data.end(), pub_bytes); + env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, JNI_COMMIT); + + jobject ec_pub_param_spec = env->NewLocalRef(ec_param_spec); + jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec); + + const Botan::BigInt& priv_scalar = skey->private_value(); + std::vector<uint8_t> priv_data = Botan::BigInt::encode(priv_scalar); + + jbyteArray priv_bytearray = env->NewByteArray(priv_data.size()); + jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL); + std::copy(priv_data.begin(), priv_data.end(), priv_bytes); + env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, JNI_COMMIT); + + jobject ec_priv_param_spec = env->NewLocalRef(ec_param_spec); + jmethodID ec_priv_init = env->GetMethodID(privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject privkey = env->NewObject(privkey_class, ec_priv_init, priv_bytearray, ec_priv_param_spec); + + jmethodID keypair_init = env->GetMethodID(keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + + return env->NewObject(keypair_class, keypair_init, pubkey, privkey); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){ + const std::set<std::string>& curves = Botan::EC_Group::known_named_groups(); + for (auto it = curves.begin(); it != curves.end(); ++it) { + Botan::EC_Group curve_group = Botan::EC_Group(*it); + size_t curve_size = curve_group.get_curve().get_p().bits(); + if (curve_size == keysize) { + //generate on this group. Even thou no default groups are present... + return generate_from_group(env, self, curve_group); + } + } + + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random){ + Botan::EC_Group curve_group = group_from_params(env, params); + return generate_from_group(env, self, curve_group); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params){ + Botan::EC_Group curve_group = group_from_params(env, params); + + jsize privkey_length = env->GetArrayLength(privkey); + jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL); + Botan::BigInt privkey_scalar((unsigned uint8_t*) 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); + jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL); + Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve()); + env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT); + + Botan::ECDH_PublicKey pkey(curve_group, public_point); + //TODO: do check_key here? + + jclass botan_ka_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Botan"); + jfieldID type_id = env->GetFieldID(botan_ka_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) env->GetObjectField(self, type_id); + const char *type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + std::string kdf; + size_t key_len = 0; + if (type_str == "ECDH") { + kdf = "Raw"; + //key len unused + } else if (type_str == "ECDHwithSHA1KDF") { + kdf = "KDF1(SHA-1)"; + key_len = 20; + } else if (type_str == "ECDHwithSHA224KDF") { + kdf = "KDF1(SHA-224)"; + key_len = 28; + } else if (type_str == "ECDHwithSHA256KDF") { + kdf = "KDF1(SHA-256)"; + key_len = 32; + } else if (type_str == "ECDHwithSHA384KDF") { + kdf = "KDF1(SHA-384)"; + key_len = 48; + } else if (type_str == "ECDHwithSHA512KDF") { + kdf = "KDF1(SHA-512)"; + key_len = 64; + } + + Botan::PK_Key_Agreement ka(skey, rng, kdf); + + std::vector<uint8_t> derived; + try { + derived = Botan::unlock(ka.derive_key(key_len, pkey.public_value()).bits_of()); + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + return NULL; + } + jbyteArray result = env->NewByteArray(derived.size()); + jbyte *result_data = env->GetByteArrayElements(result, NULL); + std::copy(derived.begin(), derived.end(), result_data); + env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT); + + return result; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params){ + Botan::EC_Group curve_group = group_from_params(env, params); + + jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan"); + jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) env->GetObjectField(self, type_id); + const char *type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + jsize privkey_length = env->GetArrayLength(privkey); + jbyte *privkey_bytes = env->GetByteArrayElements(privkey, NULL); + Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length); + env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT); + + 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); + } else if (type_str.find("ECKCDSA") != std::string::npos) { + skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, curve_group, privkey_scalar); + } else if (type_str.find("ECGDSA") != std::string::npos) { + skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, curve_group, privkey_scalar); + } + + std::string kdf; + if (type_str.find("NONE") != std::string::npos) { + kdf = "Raw"; + } else if (type_str.find("SHA1") != std::string::npos) { + kdf = "EMSA1(SHA-1)"; + } else if (type_str.find("SHA224") != std::string::npos) { + kdf = "EMSA1(SHA-224)"; + } else if (type_str.find("SHA256") != std::string::npos) { + kdf = "EMSA1(SHA-256)"; + } else if (type_str.find("SHA384") != std::string::npos) { + kdf = "EMSA1(SHA-384)"; + } else if (type_str.find("SHA512") != std::string::npos) { + kdf = "EMSA1(SHA-512)"; + } + + Botan::PK_Signer signer(*skey, rng, kdf, Botan::DER_SEQUENCE); + + jsize data_length = env->GetArrayLength(data); + jbyte *data_bytes = env->GetByteArrayElements(data, NULL); + std::vector<uint8_t> sig; + try { + sig = signer.sign_message((uint8_t*) data_bytes, data_length, rng); + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + return NULL; + } + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + + jbyteArray result = env->NewByteArray(sig.size()); + jbyte *result_data = env->GetByteArrayElements(result, NULL); + std::copy(sig.begin(), sig.end(), result_data); + env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT); + + return result; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params){ + Botan::EC_Group curve_group = group_from_params(env, params); + + jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan"); + jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) env->GetObjectField(self, type_id); + const char *type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + jsize pubkey_length = env->GetArrayLength(pubkey); + jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL); + Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve()); + env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT); + + std::unique_ptr<Botan::EC_PublicKey> pkey; + if (type_str.find("ECDSA") != std::string::npos) { + pkey = std::make_unique<Botan::ECDSA_PublicKey>(curve_group, public_point); + } else if (type_str.find("ECKCDSA") != std::string::npos) { + pkey = std::make_unique<Botan::ECKCDSA_PublicKey>(curve_group, public_point); + } else if (type_str.find("ECGDSA") != std::string::npos) { + pkey = std::make_unique<Botan::ECGDSA_PublicKey>(curve_group, public_point); + } + + std::string kdf; + if (type_str.find("NONE") != std::string::npos) { + kdf = "Raw"; + } else if (type_str.find("SHA1") != std::string::npos) { + kdf = "EMSA1(SHA-1)"; + } else if (type_str.find("SHA224") != std::string::npos) { + kdf = "EMSA1(SHA-224)"; + } else if (type_str.find("SHA256") != std::string::npos) { + kdf = "EMSA1(SHA-256)"; + } else if (type_str.find("SHA384") != std::string::npos) { + kdf = "EMSA1(SHA-384)"; + } else if (type_str.find("SHA512") != std::string::npos) { + kdf = "EMSA1(SHA-512)"; + } + + Botan::PK_Verifier verifier(*pkey, kdf, Botan::DER_SEQUENCE); + + jsize data_length = env->GetArrayLength(data); + jsize sig_length = env->GetArrayLength(signature); + jbyte *data_bytes = env->GetByteArrayElements(data, NULL); + jbyte *sig_bytes = env->GetByteArrayElements(signature, NULL); + + bool result; + try { + result = verifier.verify_message((uint8_t*)data_bytes, data_length, (uint8_t*)sig_bytes, sig_length); + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT); + return JNI_FALSE; + } + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT); + if (result) { + return JNI_TRUE; + } + return JNI_FALSE; +}
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c new file mode 100644 index 0000000..336f4a1 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c @@ -0,0 +1,66 @@ +#include "c_utils.h" +#include <string.h> + +jclass ec_parameter_spec_class; +jclass ecgen_parameter_spec_class; +jclass pubkey_class; +jclass privkey_class; +jclass keypair_class; +jclass elliptic_curve_class; +jclass fp_field_class; +jclass f2m_field_class; +jclass point_class; +jclass biginteger_class; +jclass illegal_state_exception_class; + +void init_classes(JNIEnv *env, const char* lib_name) { + jclass local_ec_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECParameterSpec"); + ec_parameter_spec_class = (*env)->NewGlobalRef(env, local_ec_parameter_spec_class); + + jclass local_ecgen_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECGenParameterSpec"); + ecgen_parameter_spec_class = (*env)->NewGlobalRef(env, local_ecgen_parameter_spec_class); + + const char *pubkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$"; + char pubkey_class_name[strlen(pubkey_base) + strlen(lib_name) + 1]; + pubkey_class_name[0] = 0; + strcat(pubkey_class_name, pubkey_base); + strcat(pubkey_class_name, lib_name); + + jclass local_pubkey_class = (*env)->FindClass(env, pubkey_class_name); + pubkey_class = (*env)->NewGlobalRef(env, local_pubkey_class); + + const char *privkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$"; + char privkey_class_name[strlen(privkey_base) + strlen(lib_name) + 1]; + privkey_class_name[0] = 0; + strcat(privkey_class_name, privkey_base); + strcat(privkey_class_name, lib_name); + + jclass local_privkey_class = (*env)->FindClass(env, privkey_class_name); + privkey_class = (*env)->NewGlobalRef(env, local_privkey_class); + + jclass local_keypair_class = (*env)->FindClass(env, "java/security/KeyPair"); + keypair_class = (*env)->NewGlobalRef(env, local_keypair_class); + + jclass local_elliptic_curve_class = (*env)->FindClass(env, "java/security/spec/EllipticCurve"); + elliptic_curve_class = (*env)->NewGlobalRef(env, local_elliptic_curve_class); + + jclass local_fp_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldFp"); + fp_field_class = (*env)->NewGlobalRef(env, local_fp_field_class); + + jclass local_f2m_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldF2m"); + f2m_field_class = (*env)->NewGlobalRef(env, local_f2m_field_class); + + jclass local_biginteger_class = (*env)->FindClass(env, "java/math/BigInteger"); + biginteger_class = (*env)->NewGlobalRef(env, local_biginteger_class); + + jclass local_point_class = (*env)->FindClass(env, "java/security/spec/ECPoint"); + point_class = (*env)->NewGlobalRef(env, local_point_class); + + jclass local_illegal_state_exception_class = (*env)->FindClass(env, "java/lang/IllegalStateException"); + illegal_state_exception_class = (*env)->NewGlobalRef(env, local_illegal_state_exception_class); +} + +void throw_new(JNIEnv *env, const char *class, const char *message) { + jclass clazz = (*env)->FindClass(env, class); + (*env)->ThrowNew(env, clazz, message); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h new file mode 100644 index 0000000..d925dfe --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h @@ -0,0 +1,28 @@ +#pragma once + +#include "native.h" + +/** + * Classes that are accessed alot are cached here, manually. + */ +extern jclass ec_parameter_spec_class; +extern jclass ecgen_parameter_spec_class; +extern jclass pubkey_class; +extern jclass privkey_class; +extern jclass keypair_class; +extern jclass elliptic_curve_class; +extern jclass fp_field_class; +extern jclass f2m_field_class; +extern jclass point_class; +extern jclass biginteger_class; +extern jclass illegal_state_exception_class; + +/** + * Initialize the classes. + */ +void init_classes(JNIEnv *env, const char* lib_name); + +/** + * Throw a new exception of class with message. + */ +void throw_new(JNIEnv *env, const char *class, const char *message);
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp new file mode 100644 index 0000000..cef4bfe --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp @@ -0,0 +1,59 @@ +#include "cpp_utils.hpp" + +jclass ec_parameter_spec_class; +jclass ecgen_parameter_spec_class; +jclass pubkey_class; +jclass privkey_class; +jclass keypair_class; +jclass elliptic_curve_class; +jclass fp_field_class; +jclass f2m_field_class; +jclass point_class; +jclass biginteger_class; +jclass illegal_state_exception_class; + +void init_classes(JNIEnv *env, std::string lib_name) { + jclass local_ec_parameter_spec_class = env->FindClass("java/security/spec/ECParameterSpec"); + ec_parameter_spec_class = (jclass) env->NewGlobalRef(local_ec_parameter_spec_class); + + jclass local_ecgen_parameter_spec_class = env->FindClass("java/security/spec/ECGenParameterSpec"); + ecgen_parameter_spec_class = (jclass) env->NewGlobalRef(local_ecgen_parameter_spec_class); + + std::string pubkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$"); + pubkey_class_name += lib_name; + + jclass local_pubkey_class = env->FindClass(pubkey_class_name.c_str()); + pubkey_class = (jclass) env->NewGlobalRef(local_pubkey_class); + + std::string privkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$"); + privkey_class_name += lib_name; + + jclass local_privkey_class = env->FindClass(privkey_class_name.c_str()); + privkey_class = (jclass) env->NewGlobalRef(local_privkey_class); + + jclass local_keypair_class = env->FindClass("java/security/KeyPair"); + keypair_class = (jclass) env->NewGlobalRef(local_keypair_class); + + jclass local_elliptic_curve_class = env->FindClass("java/security/spec/EllipticCurve"); + elliptic_curve_class = (jclass) env->NewGlobalRef(local_elliptic_curve_class); + + jclass local_fp_field_class = env->FindClass("java/security/spec/ECFieldFp"); + fp_field_class = (jclass) env->NewGlobalRef(local_fp_field_class); + + jclass local_f2m_field_class = env->FindClass("java/security/spec/ECFieldF2m"); + f2m_field_class = (jclass) env->NewGlobalRef(local_f2m_field_class); + + jclass local_biginteger_class = env->FindClass("java/math/BigInteger"); + biginteger_class = (jclass) env->NewGlobalRef(local_biginteger_class); + + jclass local_point_class = env->FindClass("java/security/spec/ECPoint"); + point_class = (jclass) env->NewGlobalRef(local_point_class); + + jclass local_illegal_state_exception_class = env->FindClass("java/lang/IllegalStateException"); + illegal_state_exception_class = (jclass) env->NewGlobalRef(local_illegal_state_exception_class); +} + +void throw_new(JNIEnv *env, const std::string& klass, const std::string& message) { + jclass clazz = env->FindClass(klass.c_str()); + env->ThrowNew(clazz, message.c_str()); +}
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp new file mode 100644 index 0000000..bbca521 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "native.h" +#include <string> + +/** + * Classes that are accessed alot are cached here, manually. + */ +extern jclass ec_parameter_spec_class; +extern jclass ecgen_parameter_spec_class; +extern jclass pubkey_class; +extern jclass privkey_class; +extern jclass keypair_class; +extern jclass elliptic_curve_class; +extern jclass fp_field_class; +extern jclass f2m_field_class; +extern jclass point_class; +extern jclass biginteger_class; +extern jclass illegal_state_exception_class; + +/** + * Initialize the classes. + */ +void init_classes(JNIEnv *env, std::string lib_name); + +/** + * Throw a new exception of class with message. + */ +void throw_new(JNIEnv *env, const std::string& klass, const std::string& message);
\ 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 new file mode 100644 index 0000000..d714b39 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -0,0 +1,344 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class cz_crcs_ectester_standalone_libs_TomcryptLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_TomcryptLib +#define _Included_cz_crcs_ectester_standalone_libs_TomcryptLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_TomcryptLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_TomcryptLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_BotanLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_BotanLib +#define _Included_cz_crcs_ectester_standalone_libs_BotanLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c new file mode 100644 index 0000000..29ee707 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -0,0 +1,450 @@ +#include "native.h" +#include <stdio.h> +#include <string.h> +#include <tomcrypt.h> +#include "c_utils.h" + +static prng_state ltc_prng; +static jclass provider_class; + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider(JNIEnv *env, jobject this) { + /* Create the custom provider. */ + jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$TomCrypt"); + provider_class = (*env)->NewGlobalRef(env, local_provider_class); + + jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V"); + + jstring name = (*env)->NewStringUTF(env, "libtomcrypt " SCRYPT); + double version = strtod(SCRYPT, NULL); + + return (*env)->NewObject(env, provider_class, init, name, version, name); +} + + +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup(JNIEnv *env, jobject this) { + /* Initialize libtommath as the math lib. */ + ltc_mp = ltm_desc; + + jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + jstring ec = (*env)->NewStringUTF(env, "KeyPairGenerator.EC"); + jstring ec_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$TomCrypt"); + (*env)->CallObjectMethod(env, this, provider_put, ec, ec_value); + + jstring ecdh = (*env)->NewStringUTF(env, "KeyAgreement.ECDH"); + jstring ecdh_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt"); + (*env)->CallObjectMethod(env, this, provider_put, ecdh, ecdh_value); + + jstring ecdsa = (*env)->NewStringUTF(env, "Signature.NONEwithECDSA"); + jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw"); + (*env)->CallObjectMethod(env, this, provider_put, ecdsa, ecdsa_value); + + int err; + /* register yarrow */ + if (register_prng(&yarrow_desc) == -1) { + fprintf(stderr, "Error registering Yarrow\n"); + return; + } + /* setup the PRNG */ + if ((err = rng_make_prng(128, find_prng("yarrow"), <c_prng, NULL)) != CRYPT_OK) { + fprintf(stderr, "Error setting up PRNG, %s\n", error_to_string(err)); + } + + init_classes(env, "TomCrypt"); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves(JNIEnv *env, jobject this) { + jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet"); + + jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V"); + jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr); + const ltc_ecc_set_type * curve = ltc_ecc_sets; + while (curve->size != 0) { + jstring curve_name = (*env)->NewStringUTF(env, curve->name); + (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name); + curve++; + } + + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize){ + int key_bytes = (keysize + 7) / 8; + const ltc_ecc_set_type * curve = ltc_ecc_sets; + while (curve->size != 0) { + if (curve->size == key_bytes) { + return JNI_TRUE; + } + curve++; + } + + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported(JNIEnv *env, jobject this, jobject params){ + if (params == NULL) { + return JNI_FALSE; + } + + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, curve, get_field); + + if ((*env)->IsInstanceOf(env, field, fp_field_class)) { + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = (*env)->CallObjectMethod(env, field, get_p); + + jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = (*env)->CallObjectMethod(env, curve, get_a); + + jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;"); + jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong)3); + + jmethodID biginteger_add = (*env)->GetMethodID(env, biginteger_class, "add", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;"); + jobject a_3 = (*env)->CallObjectMethod(env, a, biginteger_add, three); + + jmethodID biginteger_equals = (*env)->GetMethodID(env, biginteger_class, "equals", "(Ljava/lang/Object;)Z"); + jboolean eq = (*env)->CallBooleanMethod(env, p, biginteger_equals, a_3); + return eq; + } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) { + return JNI_FALSE; + } else { + return JNI_FALSE; + } + } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); + const ltc_ecc_set_type * curve = ltc_ecc_sets; + while (curve->size != 0) { + if (strcasecmp(utf_name, curve->name) == 0) { + (*env)->ReleaseStringUTFChars(env, name, utf_name); + return JNI_TRUE; + } + curve++; + } + return JNI_FALSE; + } else { + return JNI_FALSE; + } +} + +static jobject create_ec_param_spec(JNIEnv *env, const ltc_ecc_set_type *curve) { + jstring p_string = (*env)->NewStringUTF(env, curve->prime); + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(Ljava/lang/String;I)V"); + jobject p = (*env)->NewObject(env, biginteger_class, biginteger_init, p_string, (jint) 16); + + jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V"); + jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p); + + jmethodID biginteger_subtract = (*env)->GetMethodID(env, biginteger_class, "subtract", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;"); + jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;"); + jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong) 3); + jobject a = (*env)->CallObjectMethod(env, p, biginteger_subtract, three); + + jstring b_string = (*env)->NewStringUTF(env, curve->B); + jobject b = (*env)->NewObject(env, biginteger_class, biginteger_init, b_string, (jint) 16); + + jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a, b); + + jstring gx_string = (*env)->NewStringUTF(env, curve->Gx); + jstring gy_string = (*env)->NewStringUTF(env, curve->Gy); + jobject gx = (*env)->NewObject(env, biginteger_class, biginteger_init, gx_string, (jint) 16); + jobject gy = (*env)->NewObject(env, biginteger_class, biginteger_init, gy_string, (jint) 16); + + jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy); + + jstring n_string = (*env)->NewStringUTF(env, curve->order); + jobject n = (*env)->NewObject(env, biginteger_class, biginteger_init, n_string, (jint) 16); + + jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); + return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, (jint) 1); +} + +static char *biginteger_to_hex(JNIEnv *env, jobject big, jint bytes) { + jmethodID to_string = (*env)->GetMethodID(env, biginteger_class, "toString", "(I)Ljava/lang/String;"); + jstring big_string = (*env)->CallObjectMethod(env, big, to_string, (jint) 16); + + jsize len = (*env)->GetStringUTFLength(env, big_string); + char raw_string[len]; + (*env)->GetStringUTFRegion(env, big_string, 0, len, raw_string); + + char *result = calloc(bytes, 2); + if (len >= bytes) { + return strncpy(result, raw_string, 2*bytes); + } else { + jsize diff = bytes - len; + for (jint i = 0; i < diff*2; ++i) { + result[i] = '0'; + } + return strncpy(result + diff*2, raw_string, 2*bytes); + } +} + +static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field); + + jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); + jint bits = (*env)->CallIntMethod(env, field, get_bits); + jint bytes = (bits + 7) / 8; + + jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b); + + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = (*env)->CallObjectMethod(env, field, get_p); + + jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = (*env)->CallObjectMethod(env, params, get_g); + + jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = (*env)->CallObjectMethod(env, g, get_x); + + jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = (*env)->CallObjectMethod(env, g, get_y); + + jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = (*env)->CallObjectMethod(env, params, get_n); + + ltc_ecc_set_type *curve = calloc(sizeof(ltc_ecc_set_type), 1); + curve->size = bytes; + curve->name = ""; + curve->prime = biginteger_to_hex(env, p, bytes); + curve->B = biginteger_to_hex(env, b, bytes); + curve->order = biginteger_to_hex(env, n, bytes); + curve->Gx = biginteger_to_hex(env, gx, bytes); + curve->Gy = biginteger_to_hex(env, gy, bytes); + + return 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) { + 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); + (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, JNI_COMMIT); + + 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); + + 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); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, JNI_COMMIT); + + jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec); + + jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + + ecc_free(&key); + return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random){ + int key_bytes = (keysize + 7) / 8; + + const ltc_ecc_set_type *curve = ltc_ecc_sets; + while (curve->size != 0) { + if (curve->size == key_bytes) { + break; + } + curve++; + } + + if (curve->size == 0) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found."); + return NULL; + } + + return generate_from_curve(env, curve); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random){ + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + ltc_ecc_set_type *curve = create_curve(env, params); + jobject result = generate_from_curve(env, curve); + free(curve); + return result; + } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL); + const ltc_ecc_set_type* curve = ltc_ecc_sets; + while (curve->size != 0) { + if (strcasecmp(utf_name, curve->name) == 0) { + break; + } + curve++; + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + + return generate_from_curve(env, curve); + } else { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; + } +} + +static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ecc_set_type *curve, ecc_key *out) { + jsize priv_size = (*env)->GetArrayLength(env, privkey); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + + if (curve->size != priv_size) { + throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the private key size."); + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return JNI_FALSE; + } + + out->type = PK_PRIVATE; + out->idx = -1; + out->dp = curve; + ltc_mp.init(&out->k); + ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size); + + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return JNI_TRUE; +} + +static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_set_type *curve, ecc_key *out) { + jsize pub_size = (*env)->GetArrayLength(env, pubkey); + jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL); + + if (curve->size != (pub_size - 1) / 2) { + throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the public key size."); + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + return JNI_FALSE; + } + + out->type = PK_PUBLIC; + out->idx = -1; + out->dp = curve; + ltc_init_multi(&out->pubkey.x, &out->pubkey.y, &out->pubkey.z, NULL); + ltc_mp.set_int(out->pubkey.z, 1); + ltc_mp.unsigned_read(out->pubkey.x, pub_data + 1, (unsigned long) curve->size); + ltc_mp.unsigned_read(out->pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size); + + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + + return JNI_TRUE; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params){ + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key pub; + if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { + free(curve); + return NULL; + } + + ecc_key priv; + if (!privkey_from_bytes(env, privkey, curve, &priv)) { + free(curve); + return NULL; + } + + 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) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + return NULL; + } + + jbyteArray output = (*env)->NewByteArray(env, curve->size); + jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL); + memcpy(output_data, result, curve->size); + (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT); + + ltc_cleanup_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, &priv.k, NULL); + free(curve); + return output; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) { + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key priv; + if (!privkey_from_bytes(env, privkey, curve, &priv)) { + free(curve); + return NULL; + } + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + unsigned char result[curve->size*4]; + unsigned long output_len = curve->size*4; + int err; + if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + return NULL; + } + + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + + jbyteArray output = (*env)->NewByteArray(env, output_len); + jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL); + memcpy(output_data, result, output_len); + (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT); + + free(curve); + return output; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) { + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key pub; + if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { + free(curve); + return JNI_FALSE; + } + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + jsize sig_size = (*env)->GetArrayLength(env, signature); + jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); + + int err; + int result; + if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); + return JNI_FALSE; + } + + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); + free(curve); + return result; +}
\ No newline at end of file |
