aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp')
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp732
1 files changed, 732 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
new file mode 100644
index 0000000..0107d0d
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
@@ -0,0 +1,732 @@
+#include "native.h"
+
+#include <iostream>
+using std::cout;
+using std::cerr;
+using std::endl;
+
+#include <string>
+#include <sstream>
+using std::string;
+
+#include <stdexcept>
+using std::runtime_error;
+
+#include <cstdlib>
+using std::exit;
+
+#include "cryptopp/cryptlib.h"
+using CryptoPP::Exception;
+
+#include "cryptopp/config.h"
+using CryptoPP::byte;
+
+#include "cryptopp/osrng.h"
+using CryptoPP::AutoSeededRandomPool;
+using CryptoPP::AutoSeededX917RNG;
+
+#include "cryptopp/sha.h"
+using CryptoPP::SHA1;
+using CryptoPP::SHA224;
+using CryptoPP::SHA256;
+using CryptoPP::SHA384;
+using CryptoPP::SHA512;
+
+#include "cryptopp/aes.h"
+using CryptoPP::AES;
+
+#include "cryptopp/modarith.h"
+using CryptoPP::ModularArithmetic;
+
+#include "cryptopp/gf2n.h"
+using CryptoPP::PolynomialMod2;
+using CryptoPP::GF2NP;
+using CryptoPP::GF2NT;
+using CryptoPP::GF2NPP;
+
+#include "cryptopp/eccrypto.h"
+using CryptoPP::ECP;
+using CryptoPP::EC2N;
+using CryptoPP::ECDH;
+using CryptoPP::DL_GroupParameters_EC;
+using CryptoPP::ECDSA;
+
+#include "cryptopp/secblock.h"
+using CryptoPP::SecByteBlock;
+
+#include "cryptopp/oids.h"
+using CryptoPP::OID;
+
+// ASN1 is a namespace, not an object
+#include "cryptopp/asn.h"
+using namespace CryptoPP::ASN1;
+
+#include "cryptopp/integer.h"
+using CryptoPP::Integer;
+
+
+#include "cpp_utils.hpp"
+
+static jclass provider_class;
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Cryptopp");
+ provider_class = (jclass) env->NewGlobalRef(local_provider_class);
+
+ jmethodID init = env->GetMethodID(local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ std::string lib_name = "Crypto++";
+
+ int lib_version = CRYPTOPP_VERSION;
+ std::string info_str = std::to_string(lib_version);
+ std::stringstream ss;
+ ss << lib_name << " ";
+ ss << info_str[0];
+ for (int i = 1; i < info_str.size(); ++i) {
+ ss << "." << info_str[i];
+ }
+
+ jstring name = env->NewStringUTF(lib_name.c_str());
+ double version = lib_version / 100;
+ jstring info = env->NewStringUTF(ss.str().c_str());
+
+ return env->NewObject(provider_class, init, name, version, info);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Cryptopp_setup(JNIEnv *env, jobject self){
+ jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ add_kpg(env, "ECDH", "CryptoppECDH", self, provider_put);
+ add_kpg(env, "ECDSA", "CryptoppECDSA", self, provider_put);
+
+ add_ka(env, "ECDH", "CryptoppECDH", self, provider_put);
+
+ add_sig(env, "SHA1withECDSA", "CryptoppECDSAwithSHA1", self, provider_put);
+ add_sig(env, "SHA224withECDSA", "CryptoppECDSAwithSHA224", self, provider_put);
+ add_sig(env, "SHA256withECDSA", "CryptoppECDSAwithSHA256", self, provider_put);
+ add_sig(env, "SHA384withECDSA", "CryptoppECDSAwithSHA384", self, provider_put);
+ add_sig(env, "SHA512withECDSA", "CryptoppECDSAwithSHA512", self, provider_put);
+
+ init_classes(env, "Cryptopp");
+}
+
+template <class EC> static std::vector<OID> get_curve_oids() {
+ std::vector<OID> oids;
+ OID it = OID();
+ do {
+ it = DL_GroupParameters_EC<EC>::GetNextRecommendedParametersOID(it);
+ if (it == OID()) {
+ break;
+ }
+ oids.push_back(it);
+ } while (true);
+
+ return oids;
+}
+
+static std::vector<OID> get_all_curve_oids() {
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ std::vector<OID> ec2n_oids = get_curve_oids<EC2N>();
+
+ std::vector<OID> all_oids;
+ all_oids.insert(all_oids.end(), ecp_oids.begin(), ecp_oids.end());
+ all_oids.insert(all_oids.end(), ec2n_oids.begin(), ec2n_oids.end());
+ return all_oids;
+}
+
+static std::string oid_to_str(const OID &oid) {
+ const std::vector<CryptoPP::word32>& oid_values = oid.GetValues();
+ std::stringstream ss;
+ for (size_t i = 0; i < oid_values.size(); ++i) {
+ if(i != 0)
+ ss << ".";
+ ss << std::to_string(oid_values[i]);
+ }
+ return ss.str();
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getCurves(JNIEnv *env, jobject self){
+ jclass set_class = env->FindClass("java/util/TreeSet");
+
+ jmethodID set_ctr = env->GetMethodID(set_class, "<init>", "()V");
+ jmethodID set_add = env->GetMethodID(set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = env->NewObject(set_class, set_ctr);
+
+ std::vector<OID> all_oids = get_all_curve_oids();
+
+ for (auto oid = all_oids.begin(); oid != all_oids.end(); ++oid) {
+ jstring name_str = env->NewStringUTF(oid_to_str(*oid).c_str());
+ env->CallBooleanMethod(result, set_add, name_str);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_keysizeSupported(JNIEnv *env, jobject self, jint keysize){
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) {
+ DL_GroupParameters_EC<ECP> group(*oid);
+ if (((jint) group.GetCurve().GetField().MaxElementBitLength()) == keysize) {
+ return JNI_TRUE;
+ }
+ }
+
+ std::vector<OID> e2n_oids = get_curve_oids<EC2N>();
+ for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) {
+ DL_GroupParameters_EC<EC2N> group(*oid);
+ if (((jint) group.GetCurve().FieldSize().ConvertToLong()) == keysize) {
+ return JNI_TRUE;
+ }
+ }
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ // Any custom params should be supported.
+ return JNI_TRUE;
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ // Compare with OIDs I guess?
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+
+ std::vector<OID> all_oids = get_all_curve_oids();
+ for (auto oid = all_oids.begin(); oid != all_oids.end(); ++oid) {
+ std::string oid_s = oid_to_str(*oid);
+ if (str_name == oid_s) {
+ return JNI_TRUE;
+ }
+ }
+ }
+ return JNI_FALSE;
+}
+
+static Integer integer_from_biginteger(JNIEnv *env, jobject bigint) {
+ jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(bigint, to_byte_array);
+ jsize byte_length = env->GetArrayLength(byte_array);
+ jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL);
+ Integer result((byte *) byte_data, (size_t) byte_length);
+ env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static jobject biginteger_from_integer(JNIEnv *env, const Integer &integer) {
+ jbyteArray byte_array = (jbyteArray) env->NewByteArray(integer.MinEncodedSize());
+
+ jbyte *bigint_bytes = env->GetByteArrayElements(byte_array, NULL);
+ integer.Encode((byte *) bigint_bytes, integer.MinEncodedSize());
+ env->ReleaseByteArrayElements(byte_array, bigint_bytes, 0);
+
+ jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V");
+ return env->NewObject(biginteger_class, biginteger_init, (jint) 1, byte_array);
+}
+
+static jobject biginteger_from_polmod2(JNIEnv *env, const PolynomialMod2 &polmod) {
+ jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V");
+
+ jbyteArray mod_array = env->NewByteArray(polmod.MinEncodedSize());
+ jbyte *mod_data = env->GetByteArrayElements(mod_array, NULL);
+ polmod.Encode((byte *) mod_data, polmod.MinEncodedSize());
+ env->ReleaseByteArrayElements(mod_array, mod_data, 0);
+
+ return env->NewObject(biginteger_class, biginteger_init, (jint) 1, mod_array);
+}
+
+static std::unique_ptr<DL_GroupParameters_EC<ECP>> fp_group_from_params(JNIEnv *env, jobject params) {
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(elliptic_curve, get_field);
+
+ if (!env->IsInstanceOf(field, fp_field_class)) {
+ return nullptr;
+ }
+
+ jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = env->CallObjectMethod(elliptic_curve, get_a);
+ Integer ai = integer_from_biginteger(env, a);
+
+ jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = env->CallObjectMethod(elliptic_curve, get_b);
+ Integer bi = integer_from_biginteger(env, b);
+
+ jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = env->CallObjectMethod(params, get_g);
+
+ jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = env->CallObjectMethod(g, get_x);
+
+ jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = env->CallObjectMethod(g, get_y);
+
+ jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = env->CallObjectMethod(params, get_n);
+ Integer ni = integer_from_biginteger(env, n);
+
+ jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = env->CallIntMethod(params, get_h);
+ Integer hi(h);
+
+ jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = env->CallObjectMethod(field, get_p);
+ Integer pi = integer_from_biginteger(env, p);
+
+ ECP curve(pi, ai, bi);
+
+ Integer gxi = integer_from_biginteger(env, gx);
+ Integer gyi = integer_from_biginteger(env, gy);
+ ECP::Point g_point(gxi, gyi);
+
+ return std::make_unique<DL_GroupParameters_EC<ECP>>(curve, g_point, ni, hi);
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) {
+ std::string oid_s = oid_to_str(*oid);
+ if (str_name == oid_s) {
+ return std::make_unique<DL_GroupParameters_EC<ECP>>(*oid);
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+static std::unique_ptr<DL_GroupParameters_EC<EC2N>> f2m_group_from_params(JNIEnv *env, jobject params) {
+ if (env->IsInstanceOf(params, ec_parameter_spec_class)) {
+ jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = env->CallObjectMethod(params, get_curve);
+
+ jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = env->CallObjectMethod(elliptic_curve, get_field);
+
+ if (!env->IsInstanceOf(field, f2m_field_class)) {
+ return nullptr;
+ }
+
+ jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = env->CallObjectMethod(elliptic_curve, get_a);
+ Integer ai = integer_from_biginteger(env, a);
+
+ jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = env->CallObjectMethod(elliptic_curve, get_b);
+ Integer bi = integer_from_biginteger(env, b);
+
+ jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = env->CallObjectMethod(params, get_g);
+
+ jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = env->CallObjectMethod(g, get_x);
+
+ jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = env->CallObjectMethod(g, get_y);
+
+ jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = env->CallObjectMethod(params, get_n);
+ Integer ni = integer_from_biginteger(env, n);
+
+ jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = env->CallIntMethod(params, get_h);
+ Integer hi(h);
+
+ jmethodID get_midterms = env->GetMethodID(f2m_field_class, "getMidTermsOfReductionPolynomial", "()[I");
+ jintArray midterms = (jintArray) env->CallObjectMethod(field, get_midterms);
+ jsize midterm_length = env->GetArrayLength(midterms);
+ jint *midterm_data = env->GetIntArrayElements(midterms, NULL);
+
+ jmethodID get_m = env->GetMethodID(f2m_field_class, "getM", "()I");
+ jint m = env->CallIntMethod(field, get_m);
+
+ std::unique_ptr<GF2NP> base_field;
+ if (midterm_length == 1) {
+ //trinomial, use GF2NT
+ base_field = std::make_unique<GF2NT>((unsigned int) m, (unsigned int) midterm_data[0], 0);
+ } else {
+ //pentanomial, use GF2NPP
+ base_field = std::make_unique<GF2NPP>((unsigned int) m, (unsigned int) midterm_data[0], (unsigned int) midterm_data[1], (unsigned int) midterm_data[2], 0);
+ }
+ env->ReleaseIntArrayElements(midterms, midterm_data, JNI_ABORT);
+
+ jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B");
+ jbyteArray a_array = (jbyteArray) env->CallObjectMethod(a, to_byte_array);
+ jsize a_length = env->GetArrayLength(a_array);
+ jbyte *a_data = env->GetByteArrayElements(a_array, NULL);
+
+ jbyteArray b_array = (jbyteArray) env->CallObjectMethod(b, to_byte_array);
+ jsize b_length = env->GetArrayLength(b_array);
+ jbyte *b_data = env->GetByteArrayElements(b_array, NULL);
+
+ EC2N curve(*base_field, EC2N::FieldElement((byte *) a_data, (size_t) a_length), EC2N::FieldElement((byte *) b_data, (size_t) b_length));
+ env->ReleaseByteArrayElements(a_array, a_data, JNI_ABORT);
+ env->ReleaseByteArrayElements(b_array, b_data, JNI_ABORT);
+
+ jbyteArray gx_array = (jbyteArray) env->CallObjectMethod(gx, to_byte_array);
+ jsize gx_length = env->GetArrayLength(gx_array);
+ jbyte *gx_data = env->GetByteArrayElements(gx_array, NULL);
+ PolynomialMod2 gxm((byte *) gx_data, (size_t) gx_length);
+ env->ReleaseByteArrayElements(gx_array, gx_data, JNI_ABORT);
+
+ jbyteArray gy_array = (jbyteArray) env->CallObjectMethod(gy, to_byte_array);
+ jsize gy_length = env->GetArrayLength(gy_array);
+ jbyte *gy_data = env->GetByteArrayElements(gy_array, NULL);
+ PolynomialMod2 gym((byte *) gy_data, (size_t) gy_length);
+ env->ReleaseByteArrayElements(gy_array, gy_data, JNI_ABORT);
+
+ EC2N::Point g_point(gxm, gym);
+
+ return std::make_unique<DL_GroupParameters_EC<EC2N>>(curve, g_point, ni, hi);
+ } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (jstring) env->CallObjectMethod(params, get_name);
+ const char *utf_name = env->GetStringUTFChars(name, NULL);
+ std::string str_name(utf_name);
+ env->ReleaseStringUTFChars(name, utf_name);
+
+ std::vector<OID> e2n_oids = get_curve_oids<EC2N>();
+ for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) {
+ std::string oid_s = oid_to_str(*oid);
+ if (str_name == oid_s) {
+ return std::make_unique<DL_GroupParameters_EC<EC2N>>(*oid);
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+template <class EC> jobject finish_params(JNIEnv *env, jobject field, jobject a, jobject b, jobject gx, jobject gy, DL_GroupParameters_EC<EC> group) {
+ jmethodID point_init = env->GetMethodID(point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = env->NewObject(point_class, point_init, gx, gy);
+
+ jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, field, a, b);
+
+ // Integer GetSubgroupOrder
+ // Integer GetCofactor
+ jobject order = biginteger_from_integer(env, group.GetSubgroupOrder());
+ jint cofactor = (jint) group.GetCofactor().ConvertToLong();
+
+ jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return env->NewObject(ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order, cofactor);
+}
+
+template <class EC> jobject params_from_group(JNIEnv *env, DL_GroupParameters_EC<EC> group) {
+ return NULL;
+}
+
+template <> jobject params_from_group<ECP>(JNIEnv *env, DL_GroupParameters_EC<ECP> group) {
+ ECP curve = group.GetCurve();
+ jmethodID fp_field_init = env->GetMethodID(fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ ModularArithmetic mod = curve.GetField();
+ jobject p = biginteger_from_integer(env, mod.GetModulus());
+ jobject a = biginteger_from_integer(env, curve.GetA());
+ jobject b = biginteger_from_integer(env, curve.GetB());
+
+ jobject field = env->NewObject(fp_field_class, fp_field_init, p);
+
+ ECP::Point gp = group.GetBasePrecomputation().GetBase(group.GetGroupPrecomputation());
+ jobject gx = biginteger_from_integer(env, gp.x);
+ jobject gy = biginteger_from_integer(env, gp.y);
+ return finish_params(env, field, a, b, gx, gy, group);
+}
+
+template <> jobject params_from_group<EC2N>(JNIEnv *env, DL_GroupParameters_EC<EC2N> group) {
+ EC2N curve = group.GetCurve();
+ PolynomialMod2 mod = curve.GetField().GetModulus();
+ int m = mod.Degree();
+ unsigned int coeff_count = mod.CoefficientCount();
+ jintArray ks;
+ int to_find;
+ int found = 0;
+ if (coeff_count == 3) {
+ //trinomial
+ ks = env->NewIntArray(1);
+ to_find = 1;
+ } else if (coeff_count == 5) {
+ //pentanomial
+ ks = env->NewIntArray(3);
+ to_find = 3;
+ }
+ jint *ks_data = env->GetIntArrayElements(ks, NULL);
+ for (int i = m - 1; i > 0 && found < to_find; --i) {
+ if (mod.GetCoefficient(i) == 1) {
+ ks_data[found++] = i;
+ }
+ }
+ env->ReleaseIntArrayElements(ks, ks_data, 0);
+
+ jmethodID f2m_field_init = env->GetMethodID(f2m_field_class, "<init>", "(I[I)V");
+ jobject field = env->NewObject(f2m_field_class, f2m_field_init, (jint) m, ks);
+
+ jobject a = biginteger_from_polmod2(env, curve.GetA());
+ jobject b = biginteger_from_polmod2(env, curve.GetB());
+
+ EC2N::Point gp = group.GetBasePrecomputation().GetBase(group.GetGroupPrecomputation());
+ jobject gx = biginteger_from_polmod2(env, gp.x);
+ jobject gy = biginteger_from_polmod2(env, gp.y);
+ return finish_params(env, field, a, b, gx, gy, group);
+}
+
+template <class EC> jobject generate_from_group(JNIEnv *env, DL_GroupParameters_EC<EC> group, jobject params) {
+ AutoSeededRandomPool rng;
+ typename ECDH<EC>::Domain ec_domain(group);
+ SecByteBlock priv(ec_domain.PrivateKeyLength()), pub(ec_domain.PublicKeyLength());
+
+ try {
+ ec_domain.GenerateKeyPair(rng, priv, pub);
+ } catch (Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+
+ jbyteArray pub_bytearray = env->NewByteArray(pub.SizeInBytes());
+ jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL);
+ std::copy(pub.BytePtr(), pub.BytePtr()+pub.SizeInBytes(), pub_bytes);
+ env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, 0);
+
+ jobject ec_pub_param_spec = env->NewLocalRef(params);
+ jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec);
+
+ jbyteArray priv_bytearray = env->NewByteArray(priv.SizeInBytes());
+ jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL);
+ std::copy(priv.BytePtr(), priv.BytePtr()+priv.SizeInBytes(), priv_bytes);
+ env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, 0);
+
+ jobject ec_priv_param_spec = env->NewLocalRef(params);
+ jmethodID ec_priv_init = env->GetMethodID(privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = env->NewObject(privkey_class, ec_priv_init, priv_bytearray, ec_priv_param_spec);
+
+ jmethodID keypair_init = env->GetMethodID(keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+
+ return env->NewObject(keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){
+ std::vector<OID> ecp_oids = get_curve_oids<ECP>();
+ for (auto oid = ecp_oids.begin(); oid != ecp_oids.end(); ++oid) {
+ DL_GroupParameters_EC<ECP> group(*oid);
+ if (((jint) group.GetCurve().GetField().MaxElementBitLength()) == keysize) {
+ jobject params = params_from_group(env, group);
+ return generate_from_group<ECP>(env, group, params);
+ }
+ }
+
+ std::vector<OID> e2n_oids = get_curve_oids<EC2N>();
+ for (auto oid = e2n_oids.begin(); oid != e2n_oids.end(); ++oid) {
+ DL_GroupParameters_EC<EC2N> group(*oid);
+ if ((jint) group.GetCurve().FieldSize().ConvertToLong() == keysize) {
+ jobject params = params_from_group(env, group);
+ return generate_from_group<EC2N>(env, group, params);
+ }
+ }
+ return NULL;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Cryptopp_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) {
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+ return generate_from_group<EC2N>(env, *ec2n_group, params);
+ } else {
+ return generate_from_group<ECP>(env, *ecp_group, params);
+ }
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Cryptopp_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
+ SecByteBlock private_key((byte *) privkey_data, privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
+
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ SecByteBlock public_key((byte *) pubkey_data, pubkey_length);
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ bool success;
+ std::unique_ptr<SecByteBlock> secret;
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+ ECDH<EC2N>::Domain dh_agreement(*ec2n_group);
+
+ try {
+ secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength());
+ success = dh_agreement.Agree(*secret, private_key, public_key);
+ } catch (Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+ } else {
+ ECDH<ECP>::Domain dh_agreement(*ecp_group);
+
+ try {
+ secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength());
+ success = dh_agreement.Agree(*secret, private_key, public_key);
+ } catch (Exception & ex) {
+ throw_new(env, "java/security/GeneralSecurityException", ex.what());
+ return NULL;
+ }
+ }
+
+ jbyteArray result = env->NewByteArray(secret->size());
+ jbyte *result_data = env->GetByteArrayElements(result, NULL);
+ std::copy(secret->begin(), secret->end(), result_data);
+ env->ReleaseByteArrayElements(result, result_data, 0);
+
+ return result;
+}
+
+template <class EC, class H>
+jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray data, const Integer & private_key_x) {
+ AutoSeededRandomPool prng;
+
+ typename ECDSA<EC, H>::PrivateKey pkey;
+ pkey.Initialize(group, private_key_x);
+ typename ECDSA<EC, H>::Signer signer(pkey);
+
+ std::string signature(signer.MaxSignatureLength(), 0);
+
+ jsize data_length = env->GetArrayLength(data);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ size_t len = signer.SignMessage(prng, (byte *)data_bytes, data_length, (byte *)signature.c_str());
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ signature.resize(len);
+
+ jbyteArray result = env->NewByteArray(len);
+ jbyte *result_bytes = env->GetByteArrayElements(result, NULL);
+ std::copy(signature.begin(), signature.end(), result_bytes);
+ env->ReleaseByteArrayElements(result, result_bytes, 0);
+
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ jclass cryptopp_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Cryptopp");
+ jfieldID type_id = env->GetFieldID(cryptopp_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ jsize privkey_length = env->GetArrayLength(privkey);
+ jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
+ Integer private_key_x((byte *) privkey_data, (size_t) privkey_length);
+ env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
+
+ jbyteArray result;
+
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+ if (type_str.find("SHA1") != std::string::npos) {
+ result = sign_message<EC2N, SHA1>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ result = sign_message<EC2N, SHA224>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ result = sign_message<EC2N, SHA256>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ result = sign_message<EC2N, SHA384>(env, *ec2n_group, data, private_key_x);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ result = sign_message<EC2N, SHA512>(env, *ec2n_group, data, private_key_x);
+ }
+ } else {
+ if (type_str.find("SHA1") != std::string::npos) {
+ result = sign_message<ECP, SHA1>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ result = sign_message<ECP, SHA224>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ result = sign_message<ECP, SHA256>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ result = sign_message<ECP, SHA384>(env, *ecp_group, data, private_key_x);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ result = sign_message<ECP, SHA512>(env, *ecp_group, data, private_key_x);
+ }
+ }
+
+ return result;
+}
+
+template <class EC, class H>
+jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray data, jbyteArray signature, jbyteArray pubkey) {
+ typename EC::Point pkey_point;
+ jsize pubkey_length = env->GetArrayLength(pubkey);
+ jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL);
+ group.GetCurve().DecodePoint(pkey_point, (byte *)pubkey_data, pubkey_length);
+ env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT);
+
+ typename ECDSA<EC, H>::PublicKey pkey;
+ pkey.Initialize(group, pkey_point);
+ typename ECDSA<EC, H>::Verifier verifier(pkey);
+
+ jsize data_length = env->GetArrayLength(data);
+ jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ jsize sig_length = env->GetArrayLength(signature);
+ jbyte *sig_bytes = env->GetByteArrayElements(signature, NULL);
+ bool result = verifier.VerifyMessage((byte *)data_bytes, data_length, (byte *)sig_bytes, sig_length);
+ env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
+ env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Cryptopp_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jclass cryptopp_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Cryptopp");
+ jfieldID type_id = env->GetFieldID(cryptopp_sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring) env->GetObjectField(self, type_id);
+ const char *type_data = env->GetStringUTFChars(type, NULL);
+ std::string type_str(type_data);
+ env->ReleaseStringUTFChars(type, type_data);
+
+ std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
+ if (ecp_group == nullptr) {
+ std::unique_ptr<DL_GroupParameters_EC<EC2N>> ec2n_group = f2m_group_from_params(env, params);
+
+ if (type_str.find("SHA1") != std::string::npos) {
+ return verify_message<EC2N, SHA1>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ return verify_message<EC2N, SHA224>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ return verify_message<EC2N, SHA256>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ return verify_message<EC2N, SHA384>(env, *ec2n_group, data, signature, pubkey);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ return verify_message<EC2N, SHA512>(env, *ec2n_group, data, signature, pubkey);
+ }
+ } else {
+ if (type_str.find("SHA1") != std::string::npos) {
+ return verify_message<ECP, SHA1>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA224") != std::string::npos) {
+ return verify_message<ECP, SHA224>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA256") != std::string::npos) {
+ return verify_message<ECP, SHA256>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA384") != std::string::npos) {
+ return verify_message<ECP, SHA384>(env, *ecp_group, data, signature, pubkey);
+ } else if (type_str.find("SHA512") != std::string::npos) {
+ return verify_message<ECP, SHA512>(env, *ecp_group, data, signature, pubkey);
+ }
+ }
+ // unreachable
+ return JNI_FALSE;
+}