diff options
| author | J08nY | 2018-07-25 19:38:03 +0200 |
|---|---|---|
| committer | J08nY | 2018-07-25 21:52:29 +0200 |
| commit | 7f7d6503589c50c2990556a550c7a5f252d7d789 (patch) | |
| tree | 1495a62091374a3b81a5bce4e1c31fd731f49c35 | |
| parent | 713b14add9496ae5b3df5bb51b02d449f4ca0cef (diff) | |
| download | ECTester-7f7d6503589c50c2990556a550c7a5f252d7d789.tar.gz ECTester-7f7d6503589c50c2990556a550c7a5f252d7d789.tar.zst ECTester-7f7d6503589c50c2990556a550c7a5f252d7d789.zip | |
6 files changed, 424 insertions, 67 deletions
diff --git a/build-standalone.xml b/build-standalone.xml index 1e6a3d5..62b66de 100644 --- a/build-standalone.xml +++ b/build-standalone.xml @@ -134,6 +134,7 @@ <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$Mscng"/> <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPublicKey$Mscng"/> <class name="cz.crcs.ectester.standalone.libs.jni.NativeECPrivateKey$Mscng"/> + <class name="cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$Mscng"/> </javah> </target> </project> diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java index 277ffa7..7980773 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -1,5 +1,6 @@ package cz.crcs.ectester.standalone.libs.jni; +import cz.crcs.ectester.common.util.ByteUtil; import org.bouncycastle.util.Arrays; import java.math.BigInteger; @@ -12,10 +13,12 @@ import java.security.spec.ECParameterSpec; public abstract class NativeECPrivateKey implements ECPrivateKey { private String algorithm; private String format; + ECParameterSpec params; - public NativeECPrivateKey(String algorithm, String format) { + public NativeECPrivateKey(String algorithm, String format, ECParameterSpec params) { this.algorithm = algorithm; this.format = format; + this.params = params; } @Override @@ -28,14 +31,19 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { return format; } + @Override + public ECParameterSpec getParams() { + return params; + } + + public abstract byte[] getData(); + private static class Raw extends NativeECPrivateKey { - private byte[] keyData; - private ECParameterSpec params; + byte[] keyData; public Raw(byte[] keyData, ECParameterSpec params) { - super("EC", "raw"); + super("EC", "raw", params); this.keyData = keyData; - this.params = params; } @Override @@ -48,9 +56,8 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { return Arrays.clone(keyData); } - @Override - public ECParameterSpec getParams() { - return params; + public byte[] getData() { + return getEncoded(); } } @@ -79,8 +86,28 @@ public abstract class NativeECPrivateKey implements ECPrivateKey { } public static class Mscng extends Raw { - public Mscng(byte[] keyData, ECParameterSpec params) { + private byte[] header; + private byte[] x; + private byte[] y; + + public Mscng(byte[] header, byte[] x, byte[] y, byte[] keyData, ECParameterSpec params) { super(keyData, params); + this.header = header; + this.x = x; + this.y = y; + } + + public byte[] getHeader() { + return Arrays.clone(header); + } + + public byte[] getBlob() { + return ByteUtil.concatenate(header, x, y, keyData); + } + + @Override + public byte[] getData() { + return getBlob(); } } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java index 18cc2cb..e44ff49 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -15,10 +15,12 @@ import java.security.spec.ECPoint; public abstract class NativeECPublicKey implements ECPublicKey { private String algorithm; private String format; + ECParameterSpec params; - public NativeECPublicKey(String algorithm, String format) { + public NativeECPublicKey(String algorithm, String format, ECParameterSpec params) { this.algorithm = algorithm; this.format = format; + this.params = params; } @Override @@ -31,14 +33,19 @@ public abstract class NativeECPublicKey implements ECPublicKey { return format; } + @Override + public ECParameterSpec getParams() { + return params; + } + + public abstract byte[] getData(); + private static class ANSIX962 extends NativeECPublicKey { - private byte[] keyData; - private ECParameterSpec params; + byte[] keyData; public ANSIX962(byte[] keyData, ECParameterSpec params) { - super("EC", "ANSI X9.62"); + super("EC", "ANSI X9.62", params); this.keyData = keyData; - this.params = params; } @Override @@ -51,9 +58,8 @@ public abstract class NativeECPublicKey implements ECPublicKey { return Arrays.clone(keyData); } - @Override - public ECParameterSpec getParams() { - return params; + public byte[] getData() { + return ECUtil.toX962Uncompressed(getW(), params); } } @@ -82,8 +88,28 @@ public abstract class NativeECPublicKey implements ECPublicKey { } public static class Mscng extends ANSIX962 { - public Mscng(byte[] x, byte[] y, ECParameterSpec params) { + private byte[] header; + private byte[] x; + private byte[] y; + + public Mscng(byte[] header, byte[] x, byte[] y, ECParameterSpec params) { super(ByteUtil.concatenate(new byte[]{0x04}, x, y), params); + this.header = header; + this.x = x; + this.y = y; + } + + public byte[] getHeader() { + return Arrays.clone(header); + } + + public byte[] getBlob() { + return ByteUtil.concatenate(header, x, y); + } + + @Override + public byte[] getData() { + return getBlob(); } } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index 47d1fcc..1211519 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -61,8 +61,18 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { @Override protected byte[] engineGenerateSecret() throws IllegalStateException { - byte[] pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve()); - byte[] privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize()); + byte[] pubkey; + if (publicKey instanceof NativeECPublicKey) { + pubkey = ((NativeECPublicKey) publicKey).getData(); + } else { + pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve()); + } + byte[] privkey; + if (privateKey instanceof NativeECPrivateKey) { + privkey = ((NativeECPrivateKey) privateKey).getData(); + } else { + privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize()); + } return generateSecret(pubkey, privkey, params); } @@ -171,4 +181,39 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { super("ECDH"); } } + + public abstract static class Mscng extends NativeKeyAgreementSpi { + private String type; + + public Mscng(String type) { + this.type = type; + } + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + } + + public static class MscngECDHwithSHA1KDF extends Mscng { + public MscngECDHwithSHA1KDF() { + super("ECDHwithSHA1KDF"); + } + } + + public static class MscngECDHwithSHA256KDF extends Mscng { + public MscngECDHwithSHA256KDF() { + super("ECDHwithSHA256KDF"); + } + } + + public static class MscngECDHwithSHA384KDF extends Mscng { + public MscngECDHwithSHA384KDF() { + super("ECDHwithSHA384KDF"); + } + } + + public static class MscngECDHwithSHA512KDF extends Mscng { + public MscngECDHwithSHA512KDF() { + super("ECDHwithSHA512KDF"); + } + } } diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c index 94a0f60..aa986d1 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c @@ -23,6 +23,14 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createP JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Mscng_setup(JNIEnv *env, jobject self) { INIT_PROVIDER(env, provider_class); + ADD_KPG(env, self, "ECDH", "MscngECDH"); + ADD_KPG(env, self, "ECDSA", "MscngECDSA"); + + ADD_KA(env, self, "ECDHwithSHA1KDF", "MscngECDHwithSHA1KDF"); + ADD_KA(env, self, "ECDHwithSHA256KDF", "MscngECDHwithSHA256KDF"); + ADD_KA(env, self, "ECDHwithSHA384KDF", "MscngECDHwithSHA384KDF"); + ADD_KA(env, self, "ECDHwithSHA512KDF", "MscngECDHwithSHA512KDF"); + init_classes(env, "Mscng"); } @@ -119,6 +127,18 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa const named_curve_t *curve = lookup_curve(utf_name); (*env)->ReleaseStringUTFChars(env, name, utf_name); return curve == NULL ? JNI_FALSE : JNI_TRUE; + } else if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, curve, get_field); + + if ((*env)->IsInstanceOf(env, field, fp_field_class)) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } } else { return JNI_FALSE; } @@ -139,6 +159,16 @@ static jobject bytes_to_biginteger(JNIEnv *env, PBYTE bytes, int len) { return result; } +static void biginteger_to_bytes(JNIEnv *env, jobject bigint, PBYTE bytes, ULONG len) { + jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B"); + + jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array); + jsize byte_length = (*env)->GetArrayLength(env, byte_array); + jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL); + memcpy(bytes, &byte_data[byte_length - len], len); + (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT); +} + static jobject create_ec_param_spec(JNIEnv *env, PBYTE eccParams, ULONG paramLength) { // Taken from https://github.com/dotnet/corefx, thanks! This API is nowhere to be found. // @@ -218,12 +248,190 @@ static jobject create_ec_param_spec(JNIEnv *env, PBYTE eccParams, ULONG paramLen return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n_int, cof); } +static ULONG create_curve(JNIEnv *env, jobject params, PBYTE *curve) { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field); + + jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); + jint bits = (*env)->CallIntMethod(env, field, get_bits); + jint bytes = (bits + 7) / 8; + + jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a); + + jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b); + + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = (*env)->CallObjectMethod(env, field, get_p); + + jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = (*env)->CallObjectMethod(env, params, get_g); + + jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = (*env)->CallObjectMethod(env, g, get_x); + + jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = (*env)->CallObjectMethod(env, g, get_y); + + jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = (*env)->CallObjectMethod(env, params, get_n); + + jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I"); + jint h = (*env)->CallIntMethod(env, params, get_h); + + jmethodID get_bitlength = (*env)->GetMethodID(env, biginteger_class, "bitLength", "()I"); + jint order_bits = (*env)->CallIntMethod(env, n, get_bitlength); + jint order_bytes = (order_bits + 7) / 8; + + // header_size + 5*bytes + order_bytes + cof_size + 0 + ULONG bufSize = sizeof(BCRYPT_ECC_PARAMETER_HEADER) + 5*bytes + order_bytes + sizeof(jint) + 0; + *curve = calloc(buSize, 1); + BCRYPT_ECC_PARAMETER_HEADER *header = (BCRYPT_ECC_PARAMETER_HEADER*)*curve; + header->Version = 1; + header->CurveType = 1; //1 -> Prime short Weierstrass, 2 -> Prime Twisted Edwards, 3 -> Montgomery + header->CurveGenerationAlgId = 0; + header->cbFieldLength = bytes; + header->cbSubgroupOrder = order_bytes; + header->cbCofactor = sizeof(jint); + header->cbSeed = 0; + + PBYTE paramsStart = &(*curve)[sizeof(BCRYPT_ECC_PARAMETER_HEADER)]; + + biginteger_to_bytes(env, p, paramsStart, bytes); + biginteger_to_bytes(env, a, paramsStart + bytes, bytes); + biginteger_to_bytes(env, b, paramsStart + 2*bytes, bytes); + biginteger_to_bytes(env, gx, paramsStart + 3*bytes, bytes); + biginteger_to_bytes(env, gy, paramsStart + 4*bytes, bytes); + biginteger_to_bytes(env, n, paramsStart + 5*bytes, order_bytes); + jint *cof_ptr = (jint *) (paramsStart + 5*bytes + order_bytes); + *cof_ptr = h; + return bufSize; +} + +static bool init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR algo, jobject params) { + if (NT_FAILURE(BCryptOpenAlgorithmProvider(&handle, algo, MS_PRIMITIVE_PROVIDER, 0))) { + //err + return false; + } + + if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); + const named_curve_t *curve = lookup_curve(utf_name); + if (NT_FAILURE(BCryptSetProperty(handle, BCRYPT_ECC_CURVE_NAME, utf_name, strlen(utf_name), 0))) { + //err + return false; + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + } else if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + PBYTE curve; + ULONG curveLen = create_curve(env, params, &curve); + if (NT_FAILURE(BCryptSetProperty(handle, BCRYPT_ECC_PARAMETERS, curve, curveLen, 0))) { + //err + return false; + } + free(curve); + } + return true; +} + +static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key, jobject ec_param_spec) { + ULONG bufSize = 0; + if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &bufSize, 0))) { + //err + } + if (bufSize == 0) { + //err + } + + BYTE privBuf[bufSize]; + if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, privBuf, bufsize, &bufSize, 0))) { + //err + } + + // privBuf looks like: + // BCRYPT_ECCKEY_BLOB header + // byte[cbKey] Q.X + // byte[cbKey] Q.Y + // byte[cbKey] D + BCRYPT_ECCKEY_BLOB *privHeader = (BCRYPT_ECCKEY_BLOB*)privBuf; + PBYTE priv_x = &privBuf[sizeof(BCRYPT_ECCKEY_BLOB)]; + PBYTE priv_y = priv_x + privHeader->cbKey; + PBYTE priv = priv_y + privHeader->cbKey; + + jbyteArray header_bytes = (*env)->NewByteArray(env, sizeof(BCRYPT_ECCKEY_BLOB)); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, privHeader, sizeof(BCRYPT_ECCKEY_BLOB)); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + + jbyteArray x_bytes = (*env)->NewByteArray(env, privHeader->cbKey); + jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); + memcpy(x_data, priv_x, privHeader->cbKey); + (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); + + jbyteArray y_bytes = (*env)->NewByteArray(env, privHeader->cbKey); + jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); + memcpy(y_data, priv_y, privHeader->cbKey); + (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); + + jbyteArray priv_bytes = (*env)->NewByteArray(env, privHeader->cbKey); + jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); + memcpy(key_priv, priv, header->cbKey); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); + + jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([B[BLjava/security/spec/ECParameterSpec;)V"); + return (*env)->NewObject(env, privkey_class, ec_priv_init, header_bytes, x_bytes, y_bytes, priv_bytes, ec_priv_param_spec); +} + +static jobject key_to_pubkey(JNIEnv *env, BCRYPT_KEY_HANDLE key, jobject ec_param_spec) { + ULONG bufSize = 0; + if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &bufSize, 0))) { + //err + } + + BYTE pubBuf[bufSize]; + if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, pubBuf, bufSize, &bufSize, 0))) { + //err + } + + // pubBuf looks like: + // BCRYPT_ECCKEY_BLOB header + // byte[cbKey] Q.X + // byte[cbKey] Q.Y + BCRYPT_ECCKEY_BLOB *pubHeader = (BCRYPT_ECCKEY_BLOB*)pubBuf; + PBYTE pub_x = &pubBuf[sizeof(BCRYPT_ECCKEY_BLOB)]; + PBYTE pub_y = pub_x + pubHeader->cbKey; + + jbyteArray header_bytes = (*env)->NewByteArray(env, sizeof(BCRYPT_ECCKEY_BLOB)); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, pubHeader, sizeof(BCRYPT_ECCKEY_BLOB)); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + + jbyteArray x_bytes = (*env)->NewByteArray(env, pubHeader->cbKey); + jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); + memcpy(x_data, pub_x, pubHeader->cbKey); + (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); + + jbyteArray y_bytes = (*env)->NewByteArray(env, pubHeader->cbKey); + jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); + memcpy(y_data, pub_y, pubHeader->cbKey); + (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); + + jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([B[B[BLjava/security/spec/ECParameterSpec;)V"); + return (*env)->NewObject(env, pubkey_class, ec_pub_init, header_bytes, x_bytes, y_bytes, ec_pub_param_spec); +} + JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random){ BCRYPT_ALG_HANDLE kaHandle = NULL; BCRYPT_KEY_HANDLE key = NULL; - //TODO: CUSTOM curve with BCRYPT_ECC_PARAMETERS?? - jclass mscng_kpg_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Mscng"); jfieldID type_id = (*env)->GetFieldID(env, mscng_kpg_class, "type", "Ljava/lang/String;"); jstring type = (jstring) (*env)->GetObjectField(env, self, type_id); @@ -238,25 +446,16 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai } (*env)->ReleaseStringUTFChars(env, type, type_data); - if (NT_FAILURE(BCryptOpenAlgorithmProvider(&kaHandle, algo, MS_PRIMITIVE_PROVIDER, 0))) { + if (!init_algo(env, &kaHandle, algo, params)) { //err } - jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); - jstring name = (*env)->CallObjectMethod(env, params, get_name); - const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); - const named_curve_t *curve = lookup_curve(utf_name); - if (NT_FAILURE(BCryptSetProperty(kaHandle, BCRYPT_ECC_CURVE_NAME, utf_name, strlen(utf_name), 0))) { - //err - } - (*env)->ReleaseStringUTFChars(env, name, utf_name); - ULONG paramsSize; if (NT_FAILURE(BCryptGetProperty(kaHandle, BCRYPT_ECC_PARAMETERS, NULL, 0, ¶msSize, 0))) { //err } if (paramsSize == 0) { - //TODO: what now? + //err } BYTE params[paramsSize]; @@ -274,51 +473,91 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai //err } - ULONG bufSize; - if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &bufSize, 0))) { + jobject privkey = key_to_privkey(env, key, ec_param_spec); + jobject pubkey = key_to_pubkey(env, key, ec_param_spec); + + jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + + BCryptDestroyKey(key); + BCryptCloseAlgorithmProvider(kaHandle, 0); + return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) { + jclass mscng_ka_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Mscng"); + jfieldID type_id = (*env)->GetFieldID(env, mscng_ka_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) (*env)->GetObjectField(env, self, type_id); + const char* type_data = (*env)->GetStringUTFChars(env, type, NULL); + LPCWSTR kdf_algo; + if (strcmp(type_data, "ECDHwithSHA1KDF") == 0) { + kdf_algo = BCRYPT_SHA1_ALGORITHM; + } else if (strcmp(type_data, "ECDHwithSHA256KDF") == 0) { + kdf_algo = BCRYPT_SHA256_ALGORITHM; + } else if (strcmp(type_data, "ECDHwithSHA384KDF") == 0) { + kdf_algo = BCRYPT_SHA384_ALGORITHM; + } else if (strcmp(type_data, "ECDHwithSHA512KDF") == 0) { + kdf_algo = BCRYPT_SHA512_ALGORITHM; + } else { + //err + } + (*env)->ReleaseStringUTFChars(env, type, type_data); + + BCRYPT_ALG_HANDLE kaHandle = NULL; + + if (!init_algo(env, &kaHandle, BCRYPT_ECDH_ALGORITHM, params)) { //err } - BYTE privBuf[bufSize]; - if (NT_FAILURE(BCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, privBuf, bufsize, &bufSize, 0))) { + BCRYPT_KEY_HANDLE pkey = NULL; + BCRYPT_KEY_HANDLE skey = NULL; + + jint pub_length = (*env)->GetArrayLength(env, pubkey); + jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL); + if (NT_FAILURE(BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) { //err } + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); - // privBuf looks like: - // BCRYPT_ECCKEY_BLOB header - // byte[cbKey] Q.X - // byte[cbKey] Q.Y - // byte[cbKey] D - BCRYPT_ECCKEY_BLOB *header = (BCRYPT_ECCKEY_BLOB*)privBuf; - PBYTE x = &privBuf[sizeof(BCRYPT_ECCKEY_BLOB)]; - PBYTE y = x + header->cbKey; - PBYTE priv = y + header->cbKey; + jint priv_length = (*env)->GetArrayLength(env, privkey); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + if (NT_FAILURE(BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) { + //err + } - jbyteArray priv_bytes = (*env)->NewByteArray(env, header->cbKey); - jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); - memcpy(key_priv, priv, header->cbKey); - (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); + BCRYPT_SECRET_HANDLE ka = NULL; - 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); + if (NT_FAILURE(BCryptSecretAgreement(skey, pkey, &ka, 0))) { + //err + } - jbyteArray x_bytes = (*env)->NewByteArray(env, header->cbKey); - jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); - memcpy(x_data, x, header->cbKey); - (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); - jbyteArray y_bytes = (*env)->NewByteArray(env, header->cbKey); - jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); - memcpy(y_data, y, header->cbKey); - (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); + BCryptBufferDesc paramList = {0}; + BCryptBuffer kdfParams[1] = {0}; + kdfParams[0].BufferType = KDF_HASH_ALGORITHM; + kdfParams[0].cbBuffer = (DWORD)((wcslen(kdf_algo) + 1) * sizeof(WCHAR)); + kdfParams[0].pvBuffer = (PVOID)kdf_algo; + paramList.cBuffers = 1; + paramList.pBuffers = kdfParams; + paramList.ulVersion = BCRYPTBUFFER_VERSION; - jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec); - jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([B[BLjava/security/spec/ECParameterSpec;)V"); - jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, x_bytes, y_bytes, ec_pub_param_spec); + //TODO: Is this the actual KDF-1 or KDF-2 algo or something completely different? *This does not use the counter!!!* + ULONG bufSize = 0; + if (NT_FAILURE(BCryptDeriveKey(ka, BCRYPT_KDF_HASH, ¶mList, NULL, 0, &bufSize, 0))) { + //err + } - jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + BYTE derived[bufSize]; + if (NT_FAILURE(BCryptDeriveKey(ka, BCRYPT_KDF_HASH, ¶mList, derived, bufSize, &bufSize, 0))) { + //err + } - BCryptDestroyKey(key); + jbyteArray result = (*env)->NewByteArray(env, bufSize); + jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL); + memcpy(result_data, derived, bufSize); + (*env)->ReleaseByteArrayElements(env, result, result_data, 0); + + BCryptDestroyKey(pkey); + BCryptDestroyKey(skey); + BCryptDestroySecret(ka); BCryptCloseAlgorithmProvider(kaHandle, 0); - return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); + return result; }
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index 6e2b2bf..a4b5915 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -809,3 +809,22 @@ extern "C" { } #endif #endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif |
