From 0582131bbcabea050f6a43643b7e81e922e3acd0 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sat, 28 Jul 2018 11:45:49 +0200 Subject: Proper error handling in Mscng. --- src/cz/crcs/ectester/standalone/libs/jni/c_utils.c | 10 + src/cz/crcs/ectester/standalone/libs/jni/c_utils.h | 5 + src/cz/crcs/ectester/standalone/libs/jni/mscng.c | 1054 +++++++++++--------- 3 files changed, 570 insertions(+), 499 deletions(-) (limited to 'src') diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c index f920fc4..6954c36 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c @@ -1,4 +1,5 @@ #include "c_utils.h" +#define _ISOC99_SOURCE #include jclass ec_parameter_spec_class; @@ -64,3 +65,12 @@ void throw_new(JNIEnv *env, const char *class, const char *message) { jclass clazz = (*env)->FindClass(env, class); (*env)->ThrowNew(env, clazz, message); } + +void throw_new_var(JNIEnv *env, const char *class, const char *format, ...) { + char buffer[2048]; + va_list args; + va_start(args, format); + int res = vsnprintf(buffer, 2048, format, args); + va_end(args); + throw_new(env, class, buffer); +} \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h index 3ef8f86..2e5fa1a 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h @@ -27,6 +27,11 @@ void init_classes(JNIEnv *env, const char* lib_name); */ void throw_new(JNIEnv *env, const char *class, const char *message); +/** + * Throw a new exception of class, with formatted message. + */ +void throw_new_var(JNIEnv *env, const char *class, const char *format, ...); + /** * Some useful defines to init the provider. */ diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c index 04b0fcf..12cc13d 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c @@ -24,97 +24,97 @@ typedef struct { ULONG cbSeed; //Byte length of the seed used to generate the curve. } BCRYPT_ECC_PARAMETER_HEADER; -JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider(JNIEnv *env, jobject self){ - jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Mscng"); - provider_class = (*env)->NewGlobalRef(env, local_provider_class); +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_createProvider(JNIEnv *env, jobject self) { + jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Mscng"); + provider_class = (*env)->NewGlobalRef(env, local_provider_class); - jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); + jmethodID init = (*env)->GetMethodID(env, local_provider_class, "", "(Ljava/lang/String;DLjava/lang/String;)V"); - jstring name = (*env)->NewStringUTF(env, "Microsoft CNG"); - double version = 1.0; + jstring name = (*env)->NewStringUTF(env, "Microsoft CNG"); + double version = 1.0; - return (*env)->NewObject(env, provider_class, init, name, version, name); + return (*env)->NewObject(env, provider_class, init, name, version, name); } JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Mscng_setup(JNIEnv *env, jobject self) { - INIT_PROVIDER(env, provider_class); + INIT_PROVIDER(env, provider_class); - ADD_KPG(env, self, "ECDH", "MscngECDH"); - ADD_KPG(env, self, "ECDSA", "MscngECDSA"); + 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"); + ADD_KA(env, self, "ECDHwithSHA1KDF", "MscngECDHwithSHA1KDF"); + ADD_KA(env, self, "ECDHwithSHA256KDF", "MscngECDHwithSHA256KDF"); + ADD_KA(env, self, "ECDHwithSHA384KDF", "MscngECDHwithSHA384KDF"); + ADD_KA(env, self, "ECDHwithSHA512KDF", "MscngECDHwithSHA512KDF"); - ADD_SIG(env, self, "SHA1withECDSA", "MscngECDSAwithSHA1"); - ADD_SIG(env, self, "SHA256withECDSA", "MscngECDSAwithSHA256"); - ADD_SIG(env, self, "SHA384withECDSA", "MscngECDSAwithSHA384"); - ADD_SIG(env, self, "SHA512withECDSA", "MscngECDSAwithSHA112"); + ADD_SIG(env, self, "SHA1withECDSA", "MscngECDSAwithSHA1"); + ADD_SIG(env, self, "SHA256withECDSA", "MscngECDSAwithSHA256"); + ADD_SIG(env, self, "SHA384withECDSA", "MscngECDSAwithSHA384"); + ADD_SIG(env, self, "SHA512withECDSA", "MscngECDSAwithSHA112"); - init_classes(env, "Mscng"); + init_classes(env, "Mscng"); } typedef struct { - LPCSTR name; - ULONG bits; + LPCSTR name; + ULONG bits; } named_curve_t; static named_curve_t named_curves[] = { - {"curve25519", 256}, - {"brainpoolP160r1", 160}, - {"brainpoolP160t1", 160}, - {"brainpoolP192r1", 192}, - {"brainpoolP192t1", 192}, - {"brainpoolP224r1", 224}, - {"brainpoolP224t1", 224}, - {"brainpoolP256r1", 256}, - {"brainpoolP256t1", 256}, - {"brainpoolP320r1", 320}, - {"brainpoolP320t1", 320}, - {"brainpoolP384r1", 384}, - {"brainpoolP384t1", 384}, - {"brainpoolP512r1", 512}, - {"brainpoolP512t1", 512}, - {"ec192wapi", 192}, - {"nistP192", 192}, - {"nistP224", 224}, - {"nistP256", 256}, - {"nistP384", 384}, - {"nistP521", 521}, - {"numsP256t1", 256}, - {"numsP384t1", 384}, - {"numsP512t1", 512}, - {"secP160k1", 160}, - {"secP160r1", 160}, - {"secP160r2", 160}, - {"secP192k1", 192}, - {"secP192r1", 192}, - {"secP224k1", 224}, - {"secP224r1", 224}, - {"secP256k1", 256}, - {"secP256r1", 256}, - {"secP384r1", 384}, - {"secP521r1", 521}, - {"wtls12", 224}, - {"wtls7", 160}, - {"wtls9", 160}, - {"x962P192v1", 192}, - {"x962P192v2", 192}, - {"x962P192v3", 192}, - {"x962P239v1", 239}, - {"x962P239v2", 239}, - {"x962P239v3", 239}, - {"x962P256v1", 256} + {"curve25519", 256}, + {"brainpoolP160r1", 160}, + {"brainpoolP160t1", 160}, + {"brainpoolP192r1", 192}, + {"brainpoolP192t1", 192}, + {"brainpoolP224r1", 224}, + {"brainpoolP224t1", 224}, + {"brainpoolP256r1", 256}, + {"brainpoolP256t1", 256}, + {"brainpoolP320r1", 320}, + {"brainpoolP320t1", 320}, + {"brainpoolP384r1", 384}, + {"brainpoolP384t1", 384}, + {"brainpoolP512r1", 512}, + {"brainpoolP512t1", 512}, + {"ec192wapi", 192}, + {"nistP192", 192}, + {"nistP224", 224}, + {"nistP256", 256}, + {"nistP384", 384}, + {"nistP521", 521}, + {"numsP256t1", 256}, + {"numsP384t1", 384}, + {"numsP512t1", 512}, + {"secP160k1", 160}, + {"secP160r1", 160}, + {"secP160r2", 160}, + {"secP192k1", 192}, + {"secP192r1", 192}, + {"secP224k1", 224}, + {"secP224r1", 224}, + {"secP256k1", 256}, + {"secP256r1", 256}, + {"secP384r1", 384}, + {"secP521r1", 521}, + {"wtls12", 224}, + {"wtls7", 160}, + {"wtls9", 160}, + {"x962P192v1", 192}, + {"x962P192v2", 192}, + {"x962P192v3", 192}, + {"x962P239v1", 239}, + {"x962P239v2", 239}, + {"x962P239v3", 239}, + {"x962P256v1", 256} }; static const named_curve_t* lookup_curve(const char *name) { - for (size_t i = 0; i < sizeof(named_curves) / sizeof(named_curve_t); ++i) { - if (strcmp(name, named_curves[i].name) == 0) { - return &named_curves[i]; - } - } - return NULL; + for (size_t i = 0; i < sizeof(named_curves) / sizeof(named_curve_t); ++i) { + if (strcmp(name, named_curves[i].name) == 0) { + return &named_curves[i]; + } + } + return NULL; } static const named_curve_t* lookup_curve_bits(jint bitsize) { @@ -161,24 +161,25 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurv BCRYPT_ALG_HANDLE handle; if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&handle, BCRYPT_ECDH_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) { - //err wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); - return 0; + return result; } ULONG bufSize; if (NT_FAILURE(status = BCryptGetProperty(handle, BCRYPT_ECC_CURVE_NAME_LIST, NULL, 0, &bufSize, 0))) { - //err wprintf(L"**** Error 0x%x returned by BCryptGetProperty(length only)\n", status); - return 0; + BCryptCloseAlgorithmProvider(handle, 0); + return result; } BCRYPT_ECC_CURVE_NAMES *curves = (BCRYPT_ECC_CURVE_NAMES *)calloc(bufSize, 1); - if (NT_FAILURE(status = BCryptGetProperty(handle, BCRYPT_ECC_CURVE_NAME_LIST, (PBYTE) curves, bufSize, &bufSize, 0))) { - //err + if (NT_FAILURE(status = BCryptGetProperty(handle, BCRYPT_ECC_CURVE_NAME_LIST, (PBYTE)curves, bufSize, &bufSize, 0))) { wprintf(L"**** Error 0x%x returned by BCryptGetProperty(whole)\n", status); - return 0; + BCryptCloseAlgorithmProvider(handle, 0); + free(curves); + return result; } + for (size_t i = 0; i < curves->dwEccCurveNames; ++i) { NPSTR curve_name; ULONG len = utf_16to8(&curve_name, curves->pEccCurveNames[i]); @@ -190,7 +191,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getCurv free(curves); BCryptCloseAlgorithmProvider(handle, 0); - return result; + return result; } JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_keysizeSupported(JNIEnv *env, jobject self, jint keysize) { @@ -206,55 +207,55 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPa JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Mscng_paramsSupported(JNIEnv *env, jobject self, jobject params) { if (params == NULL) { - return JNI_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); - (*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; - } + return JNI_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); + (*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; + } } static jobject bytes_to_biginteger(JNIEnv *env, PBYTE bytes, int len) { - jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); - jbyteArray byte_array = (*env)->NewByteArray(env, len); - jbyte *data = (*env)->GetByteArrayElements(env, byte_array, NULL); - memcpy(data, bytes, len); - (*env)->ReleaseByteArrayElements(env, byte_array, data, 0); - jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, byte_array); - return result; + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "", "(I[B)V"); + jbyteArray byte_array = (*env)->NewByteArray(env, len); + jbyte *data = (*env)->GetByteArrayElements(env, byte_array, NULL); + memcpy(data, bytes, len); + (*env)->ReleaseByteArrayElements(env, byte_array, data, 0); + jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, byte_array); + 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"); + 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); + 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, PULONG paramLength) { - // + // // BCRYPT_ECCFULLKEY_BLOB header // P[cbFieldLength] Prime specifying the base field. // A[cbFieldLength] Coefficient A of the equation y^2 = x^3 + A*x + B mod p @@ -266,151 +267,148 @@ static jobject create_ec_param_spec(JNIEnv *env, PBYTE eccParams, PULONG paramLe // S[cbSeed] Seed of the curve. BCRYPT_ECCFULLKEY_BLOB *header = (BCRYPT_ECCFULLKEY_BLOB*)eccParams; - PBYTE paramsStart = &eccParams[sizeof(BCRYPT_ECCFULLKEY_BLOB)]; + PBYTE paramsStart = &eccParams[sizeof(BCRYPT_ECCFULLKEY_BLOB)]; - //cbFieldLength - PBYTE P = paramsStart; - PBYTE A = P + header->cbFieldLength; - PBYTE B = A + header->cbFieldLength; - PBYTE GX = B + header->cbFieldLength; - PBYTE GY = GX + header->cbFieldLength; + //cbFieldLength + PBYTE P = paramsStart; + PBYTE A = P + header->cbFieldLength; + PBYTE B = A + header->cbFieldLength; + PBYTE GX = B + header->cbFieldLength; + PBYTE GY = GX + header->cbFieldLength; - //cbSubgroupOrder - PBYTE N = GY + header->cbFieldLength; + //cbSubgroupOrder + PBYTE N = GY + header->cbFieldLength; - //cbCofactor - PBYTE H = N + header->cbSubgroupOrder; + //cbCofactor + PBYTE H = N + header->cbSubgroupOrder; - //cbSeed - PBYTE S = H + header->cbCofactor; + //cbSeed + PBYTE S = H + header->cbCofactor; *paramLength = sizeof(BCRYPT_ECCFULLKEY_BLOB) + 5 * header->cbFieldLength + header->cbSubgroupOrder + header->cbCofactor + header->cbSeed; - jobject p_int = bytes_to_biginteger(env, P, header->cbFieldLength); + jobject p_int = bytes_to_biginteger(env, P, header->cbFieldLength); - jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "", "(Ljava/math/BigInteger;)V"); - jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int); + jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "", "(Ljava/math/BigInteger;)V"); + jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int); - jobject a_int = bytes_to_biginteger(env, A, header->cbFieldLength); - jobject b_int = bytes_to_biginteger(env, B, header->cbFieldLength); + jobject a_int = bytes_to_biginteger(env, A, header->cbFieldLength); + jobject b_int = bytes_to_biginteger(env, B, header->cbFieldLength); - jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); - jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int); + jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int); - jobject gx_int = bytes_to_biginteger(env, GX, header->cbFieldLength); - jobject gy_int = bytes_to_biginteger(env, GY, header->cbFieldLength); + jobject gx_int = bytes_to_biginteger(env, GX, header->cbFieldLength); + jobject gy_int = bytes_to_biginteger(env, GY, header->cbFieldLength); - jmethodID point_init = (*env)->GetMethodID(env, point_class, "", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); - jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int); + jmethodID point_init = (*env)->GetMethodID(env, point_class, "", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int); - jobject n_int = bytes_to_biginteger(env, N, header->cbSubgroupOrder); + jobject n_int = bytes_to_biginteger(env, N, header->cbSubgroupOrder); - jobject h_int = bytes_to_biginteger(env, H, header->cbCofactor); - jmethodID bigint_to_int = (*env)->GetMethodID(env, biginteger_class, "intValue", "()I"); - jint cof = (*env)->CallIntMethod(env, h_int, bigint_to_int); + jobject h_int = bytes_to_biginteger(env, H, header->cbCofactor); + jmethodID bigint_to_int = (*env)->GetMethodID(env, biginteger_class, "intValue", "()I"); + jint cof = (*env)->CallIntMethod(env, h_int, bigint_to_int); - jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "", "(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_int, cof); + jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "", "(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_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_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_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_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_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_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_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_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_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_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_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_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; + 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 + 1 + 0; - *curve = calloc(bufSize, 1); - BCRYPT_ECC_PARAMETER_HEADER *header = (BCRYPT_ECC_PARAMETER_HEADER*)*curve; - header->dwVersion = 1; - header->dwCurveType = 1; //1 -> Prime short Weierstrass, 2 -> Prime Twisted Edwards, 3 -> Montgomery - header->dwCurveGenerationAlgId = 0; - header->cbFieldLength = bytes; - header->cbSubgroupOrder = order_bytes; + // header_size + 5*bytes + order_bytes + cof_size + 0 + ULONG bufSize = sizeof(BCRYPT_ECC_PARAMETER_HEADER) + 5 * bytes + order_bytes + 1 + 0; + *curve = calloc(bufSize, 1); + BCRYPT_ECC_PARAMETER_HEADER *header = (BCRYPT_ECC_PARAMETER_HEADER*)*curve; + header->dwVersion = 1; + header->dwCurveType = 1; //1 -> Prime short Weierstrass, 2 -> Prime Twisted Edwards, 3 -> Montgomery + header->dwCurveGenerationAlgId = 0; + header->cbFieldLength = bytes; + header->cbSubgroupOrder = order_bytes; header->cbCofactor = 1; - header->cbSeed = 0; + header->cbSeed = 0; - PBYTE paramsStart = &(*curve)[sizeof(BCRYPT_ECC_PARAMETER_HEADER)]; + 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); - PBYTE cof_ptr = (PBYTE) (paramsStart + 5*bytes + order_bytes); + 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); + PBYTE cof_ptr = (PBYTE)(paramsStart + 5 * bytes + order_bytes); *cof_ptr = (BYTE)h; - return bufSize; + return bufSize; } static ULONG init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR algo, jobject params) { NTSTATUS status; - if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(handle, algo, MS_PRIMITIVE_PROVIDER, 0))) { - //err + if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(handle, algo, MS_PRIMITIVE_PROVIDER, 0))) { wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); - return 0; - } + return 0; + } ULONG result = 0; - 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); + 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); jint utf_length = (*env)->GetStringUTFLength(env, name); PUCHAR chars = calloc(utf_length + 1, 1); (*env)->GetStringUTFRegion(env, name, 0, utf_length, chars); - const named_curve_t *curve = lookup_curve(chars); + const named_curve_t *curve = lookup_curve(chars); NWPSTR curve_utf16; ULONG ret = utf_8to16(&curve_utf16, chars); - if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, (PUCHAR) curve_utf16, ret * sizeof(WCHAR), 0))) { - //err + if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, (PUCHAR)curve_utf16, ret * sizeof(WCHAR), 0))) { wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status); - return 0; - } + return 0; + } free(chars); free(curve_utf16); result = curve->bits; - } else if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { - PBYTE curve; - ULONG curveLen = create_curve(env, params, &curve); - if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_PARAMETERS, curve, curveLen, 0))) { - //err + } else if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + PBYTE curve; + ULONG curveLen = create_curve(env, params, &curve); + if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_PARAMETERS, curve, curveLen, 0))) { wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status); - return 0; - } - free(curve); + return 0; + } + free(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); @@ -421,27 +419,24 @@ static ULONG init_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR algo, job jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); jint bits = (*env)->CallIntMethod(env, field, get_bits); result = bits; - } - return result; + } + return result; } static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { NTSTATUS status; - ULONG bufSize = 0; - if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, NULL, 0, &bufSize, 0))) { - //err + ULONG bufSize = 0; + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, NULL, 0, &bufSize, 0))) { wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, length only)\n", status); return NULL; - } - if (bufSize == 0) { - //err - printf("err0\n"); + } + if (bufSize == 0) { + printf("buf 0\n"); return NULL; - } + } PBYTE fullBuf = calloc(bufSize, 1); - if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, fullBuf, bufSize, &bufSize, 0))) { - //err + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, fullBuf, bufSize, &bufSize, 0))) { wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, whole)\n", status); return NULL; } @@ -449,7 +444,7 @@ static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { ULONG paramLength; jobject ec_priv_param_spec = create_ec_param_spec(env, fullBuf, ¶mLength); - // fullBuf looks like: + // fullBuf looks like: // BCRYPT_ECCFULLKEY_BLOB header // P[cbFieldLength] Prime specifying the base field. // A[cbFieldLength] Coefficient A of the equation y^2 = x^3 + A*x + B mod p @@ -463,56 +458,53 @@ static jobject key_to_privkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { // Qy[cbFieldLength] Y-coordinate of the public point. // d[cbSubgroupOrder] Private key. BCRYPT_ECCFULLKEY_BLOB *privHeader = (BCRYPT_ECCFULLKEY_BLOB*)fullBuf; - PBYTE priv_x = &fullBuf[paramLength]; - PBYTE priv_y = priv_x + privHeader->cbFieldLength; - PBYTE priv = priv_y + privHeader->cbFieldLength; - - jbyteArray header_bytes = (*env)->NewByteArray(env, paramLength); - jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); - memcpy(header_data, privHeader, paramLength); - (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); - - jbyteArray x_bytes = (*env)->NewByteArray(env, privHeader->cbFieldLength); - jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); - memcpy(x_data, priv_x, privHeader->cbFieldLength); - (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); - - jbyteArray y_bytes = (*env)->NewByteArray(env, privHeader->cbFieldLength); - jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); - memcpy(y_data, priv_y, privHeader->cbFieldLength); - (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); - - jbyteArray priv_bytes = (*env)->NewByteArray(env, privHeader->cbSubgroupOrder); - jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); - memcpy(key_priv, priv, privHeader->cbSubgroupOrder); - (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); + PBYTE priv_x = &fullBuf[paramLength]; + PBYTE priv_y = priv_x + privHeader->cbFieldLength; + PBYTE priv = priv_y + privHeader->cbFieldLength; + + jbyteArray header_bytes = (*env)->NewByteArray(env, paramLength); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, privHeader, paramLength); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + + jbyteArray x_bytes = (*env)->NewByteArray(env, privHeader->cbFieldLength); + jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); + memcpy(x_data, priv_x, privHeader->cbFieldLength); + (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); + + jbyteArray y_bytes = (*env)->NewByteArray(env, privHeader->cbFieldLength); + jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); + memcpy(y_data, priv_y, privHeader->cbFieldLength); + (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); + + jbyteArray priv_bytes = (*env)->NewByteArray(env, privHeader->cbSubgroupOrder); + jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); + memcpy(key_priv, priv, privHeader->cbSubgroupOrder); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0); free(fullBuf); - - jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "", "([B[B[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); + + jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "", "([B[B[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) { NTSTATUS status; - ULONG bufSize = 0; - if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, NULL, 0, &bufSize, 0))) { - //err + ULONG bufSize = 0; + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, NULL, 0, &bufSize, 0))) { wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, length only)\n", status); return NULL; - } + } if (bufSize == 0) { - //err printf("err0\n"); return NULL; } PBYTE fullBuf = calloc(bufSize, 1); - if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, fullBuf, bufSize, &bufSize, 0))) { - //err + if (NT_FAILURE(status = BCryptExportKey(key, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, fullBuf, bufSize, &bufSize, 0))) { wprintf(L"**** Error 0x%x returned by BCryptExportKey(full, whole)\n", status); return NULL; - } + } ULONG paramLength; jobject ec_pub_param_spec = create_ec_param_spec(env, fullBuf, ¶mLength); @@ -530,28 +522,28 @@ static jobject key_to_pubkey(JNIEnv *env, BCRYPT_KEY_HANDLE key) { // Qx[cbFieldLength] X-coordinate of the public point. // Qy[cbFieldLength] Y-coordinate of the public point. BCRYPT_ECCFULLKEY_BLOB *pubHeader = (BCRYPT_ECCFULLKEY_BLOB*)fullBuf; - PBYTE pub_x = &fullBuf[paramLength]; - PBYTE pub_y = pub_x + pubHeader->cbFieldLength; + PBYTE pub_x = &fullBuf[paramLength]; + PBYTE pub_y = pub_x + pubHeader->cbFieldLength; - jbyteArray header_bytes = (*env)->NewByteArray(env, paramLength); - jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); - memcpy(header_data, pubHeader, paramLength); - (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); + jbyteArray header_bytes = (*env)->NewByteArray(env, paramLength); + jbyte *header_data = (*env)->GetByteArrayElements(env, header_bytes, NULL); + memcpy(header_data, pubHeader, paramLength); + (*env)->ReleaseByteArrayElements(env, header_bytes, header_data, 0); - jbyteArray x_bytes = (*env)->NewByteArray(env, pubHeader->cbFieldLength); - jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); - memcpy(x_data, pub_x, pubHeader->cbFieldLength); - (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); + jbyteArray x_bytes = (*env)->NewByteArray(env, pubHeader->cbFieldLength); + jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL); + memcpy(x_data, pub_x, pubHeader->cbFieldLength); + (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0); - jbyteArray y_bytes = (*env)->NewByteArray(env, pubHeader->cbFieldLength); - jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); - memcpy(y_data, pub_y, pubHeader->cbFieldLength); - (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); + jbyteArray y_bytes = (*env)->NewByteArray(env, pubHeader->cbFieldLength); + jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL); + memcpy(y_data, pub_y, pubHeader->cbFieldLength); + (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0); free(fullBuf); - jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "", "([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); + jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "", "([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__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) { @@ -575,8 +567,8 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai algo = BCRYPT_ECDH_P521_ALGORITHM; break; default: - //err - break; + //unreachable + return NULL; } } else if (strcmp(type_data, "ECDSA") == 0) { switch (keysize) { @@ -590,28 +582,32 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai algo = BCRYPT_ECDSA_P521_ALGORITHM; break; default: - //err - break; + //unreachable + return NULL; } } else { - //err + //unreachable + return NULL; } (*env)->ReleaseStringUTFChars(env, type, type_data); if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&handle, algo, MS_PRIMITIVE_PROVIDER, 0))) { - //err - wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider", status); return NULL; } BCRYPT_KEY_HANDLE key = NULL; if (NT_FAILURE(status = BCryptGenerateKeyPair(handle, &key, keysize, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptGenerateKeyPair\n", status); + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGenerateKeyPair\n", status); + BCryptCloseAlgorithmProvider(handle, 0); + return NULL; } if (NT_FAILURE(status = BCryptFinalizeKeyPair(key, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptFinalizeKeyPair\n", status); + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptFinalizeKeyPair\n", status); + BCryptCloseAlgorithmProvider(handle, 0); + return NULL; } jobject privkey = key_to_privkey(env, key); @@ -624,276 +620,336 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); } -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){ +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) { NTSTATUS status; - BCRYPT_ALG_HANDLE handle = NULL; - BCRYPT_KEY_HANDLE key = NULL; - - 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); - const char* type_data = (*env)->GetStringUTFChars(env, type, NULL); - LPCWSTR algo; - if (strcmp(type_data, "ECDH") == 0) { - algo = BCRYPT_ECDH_ALGORITHM; - } else if (strcmp(type_data, "ECDSA") == 0) { - algo = BCRYPT_ECDSA_ALGORITHM; - } else { - //err - } - (*env)->ReleaseStringUTFChars(env, type, type_data); + BCRYPT_ALG_HANDLE handle = NULL; + BCRYPT_KEY_HANDLE key = NULL; + + 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); + const char* type_data = (*env)->GetStringUTFChars(env, type, NULL); + LPCWSTR algo; + if (strcmp(type_data, "ECDH") == 0) { + algo = BCRYPT_ECDH_ALGORITHM; + } else if (strcmp(type_data, "ECDSA") == 0) { + algo = BCRYPT_ECDSA_ALGORITHM; + } else { + //unreachable + return NULL; + } + (*env)->ReleaseStringUTFChars(env, type, type_data); ULONG bits = init_algo(env, &handle, algo, params); - if (bits == 0) { - //err - } + if (bits == 0) { + throw_new(env, "java/security/GeneralSecurityException", "Couldn't initialize algo."); + return NULL; + } - if (NT_FAILURE(status = BCryptGenerateKeyPair(handle, &key, bits, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptGenerateKeyPair\n", status); - } + if (NT_FAILURE(status = BCryptGenerateKeyPair(handle, &key, bits, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGenerateKeyPair\n", status); + BCryptCloseAlgorithmProvider(handle, 0); + return NULL; + } - if (NT_FAILURE(status = BCryptFinalizeKeyPair(key, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptFinalizeKeyPair\n", status); - } + if (NT_FAILURE(status = BCryptFinalizeKeyPair(key, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptFinalizeKeyPair\n", status); + BCryptCloseAlgorithmProvider(handle, 0); + return NULL; + } - jobject privkey = key_to_privkey(env, key); - jobject pubkey = key_to_pubkey(env, key); + jobject privkey = key_to_privkey(env, key); + jobject pubkey = key_to_pubkey(env, key); - jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); - BCryptDestroyKey(key); - BCryptCloseAlgorithmProvider(handle, 0); - return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); + BCryptDestroyKey(key); + BCryptCloseAlgorithmProvider(handle, 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) { NTSTATUS status; printf("generateSecret!\n"); - 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 - } - - 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(status = BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair(pub)\n", status); - } - (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); - - jint priv_length = (*env)->GetArrayLength(env, privkey); - jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); - if (NT_FAILURE(status = BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair(priv)\n", status); - } - (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); - - BCRYPT_SECRET_HANDLE ka = NULL; - - if (NT_FAILURE(status = BCryptSecretAgreement(skey, pkey, &ka, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptSecretAgreement\n", status); - } - - 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; - - //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(status = BCryptDeriveKey(ka, BCRYPT_KDF_HASH, ¶mList, NULL, 0, &bufSize, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptDeriveKey(length only)\n", status); - } + 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 { + //unreachable + return NULL; + } + (*env)->ReleaseStringUTFChars(env, type, type_data); + + BCRYPT_ALG_HANDLE kaHandle = NULL; + + ULONG bits = init_algo(env, &kaHandle, BCRYPT_ECDH_ALGORITHM, params); + if (bits == 0) { + throw_new(env, "java/security/GeneralSecurityException", "Couldn't initialize algo."); + return NULL; + } + + 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(status = BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair(pub)\n", status); + BCryptCloseAlgorithmProvider(kaHandle, 0); + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + return NULL; + } + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + + jint priv_length = (*env)->GetArrayLength(env, privkey); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + if (NT_FAILURE(status = BCryptImportKeyPair(kaHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair(priv)\n", status); + BCryptCloseAlgorithmProvider(kaHandle, 0); + BCryptDestroyKey(pkey); + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return NULL; + } + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + + BCRYPT_SECRET_HANDLE ka = NULL; + + if (NT_FAILURE(status = BCryptSecretAgreement(skey, pkey, &ka, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSecretAgreement\n", status); + BCryptCloseAlgorithmProvider(kaHandle, 0); + BCryptDestroyKey(pkey); + BCryptDestroyKey(skey); + return NULL; + } + + 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; + + //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(status = BCryptDeriveKey(ka, BCRYPT_KDF_HASH, ¶mList, NULL, 0, &bufSize, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptDeriveKey(length only)\n", status); + return NULL; + } PBYTE derived = calloc(bufSize, 1); - if (NT_FAILURE(status = BCryptDeriveKey(ka, BCRYPT_KDF_HASH, ¶mList, derived, bufSize, &bufSize, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptDeriveKey(whole)\n", status); - } + if (NT_FAILURE(status = BCryptDeriveKey(ka, BCRYPT_KDF_HASH, ¶mList, derived, bufSize, &bufSize, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptDeriveKey(whole)\n", status); + return NULL; + } - 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); + 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); free(derived); - BCryptDestroyKey(pkey); - BCryptDestroyKey(skey); - BCryptDestroySecret(ka); - BCryptCloseAlgorithmProvider(kaHandle, 0); - return result; + BCryptDestroyKey(pkey); + BCryptDestroyKey(skey); + BCryptDestroySecret(ka); + BCryptCloseAlgorithmProvider(kaHandle, 0); + return result; } static LPCWSTR get_sighash_algo(JNIEnv *env, jobject self) { - jclass mscng_sig_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Mscng"); - jfieldID type_id = (*env)->GetFieldID(env, mscng_sig_class, "type", "Ljava/lang/String;"); - jstring type = (jstring) (*env)->GetObjectField(env, self, type_id); - const char* type_data = (*env)->GetStringUTFChars(env, type, NULL); - LPCWSTR hash_algo; - if (strcmp(type_data, "SHA1withECDSA") == 0) { - hash_algo = BCRYPT_SHA1_ALGORITHM; - } else if (strcmp(type_data, "SHA256withECDSA") == 0) { - hash_algo = BCRYPT_SHA256_ALGORITHM; - } else if (strcmp(type_data, "SHA384withECDSA") == 0) { - hash_algo = BCRYPT_SHA384_ALGORITHM; - } else if (strcmp(type_data, "SHA512withECDSA") == 0) { - hash_algo = BCRYPT_SHA512_ALGORITHM; - } else { - //err - } - (*env)->ReleaseStringUTFChars(env, type, type_data); - return hash_algo; + jclass mscng_sig_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Mscng"); + jfieldID type_id = (*env)->GetFieldID(env, mscng_sig_class, "type", "Ljava/lang/String;"); + jstring type = (jstring)(*env)->GetObjectField(env, self, type_id); + const char* type_data = (*env)->GetStringUTFChars(env, type, NULL); + LPCWSTR hash_algo; + if (strcmp(type_data, "SHA1withECDSA") == 0) { + hash_algo = BCRYPT_SHA1_ALGORITHM; + } else if (strcmp(type_data, "SHA256withECDSA") == 0) { + hash_algo = BCRYPT_SHA256_ALGORITHM; + } else if (strcmp(type_data, "SHA384withECDSA") == 0) { + hash_algo = BCRYPT_SHA384_ALGORITHM; + } else if (strcmp(type_data, "SHA512withECDSA") == 0) { + hash_algo = BCRYPT_SHA512_ALGORITHM; + } else { + //unreachable + return NULL; + } + (*env)->ReleaseStringUTFChars(env, type, type_data); + return hash_algo; } JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) { NTSTATUS status; - LPCWSTR hash_algo = get_sighash_algo(env, self); + LPCWSTR hash_algo = get_sighash_algo(env, self); - BCRYPT_ALG_HANDLE sigHandle = NULL; + BCRYPT_ALG_HANDLE sigHandle = NULL; if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&sigHandle, BCRYPT_ECDSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) { - //err - wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); - return 0; + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); + return NULL; } - BCRYPT_ALG_HANDLE hashHandle = NULL; + BCRYPT_ALG_HANDLE hashHandle = NULL; - if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&hashHandle, hash_algo, NULL, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); - } + if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&hashHandle, hash_algo, NULL, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + return NULL; + } - DWORD dummy = 0; - DWORD hash_len = 0; - if (NT_FAILURE(status = BCryptGetProperty(hashHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hash_len, sizeof(DWORD), &dummy, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptGetProperty(hash len)\n", status); - } + DWORD dummy = 0; + DWORD hash_len = 0; + if (NT_FAILURE(status = BCryptGetProperty(hashHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hash_len, sizeof(DWORD), &dummy, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGetProperty(hash len)\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + return NULL; + } PBYTE hash = calloc(hash_len, 1); - jint data_len = (*env)->GetArrayLength(env, data); - jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL); - if (NT_FAILURE(status = BCryptHash(hashHandle, NULL, 0, data_bytes, data_len, hash, hash_len))) { - wprintf(L"**** Error 0x%x returned by BCryptHash\n", status); - } - (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT); - - BCRYPT_KEY_HANDLE skey = NULL; - - jint priv_length = (*env)->GetArrayLength(env, privkey); - jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); - if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair\n", status); - } - (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); - - DWORD sig_len = 0; - if (NT_FAILURE(status = BCryptSignHash(skey, NULL, hash, hash_len, NULL, 0, &sig_len, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptSignHash(len only)\n", status); - } - - jbyteArray sig = (*env)->NewByteArray(env, sig_len); - jbyte *sig_data = (*env)->GetByteArrayElements(env, sig, NULL); - if (NT_FAILURE(status = BCryptSignHash(skey, NULL, hash, hash_len, sig_data, sig_len, &sig_len, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptSignHash(do)\n", status); - } - (*env)->ReleaseByteArrayElements(env, sig, sig_data, 0); + jint data_len = (*env)->GetArrayLength(env, data); + jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL); + if (NT_FAILURE(status = BCryptHash(hashHandle, NULL, 0, data_bytes, data_len, hash, hash_len))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptHash\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + free(hash); + (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT); + return NULL; + } + (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT); + + BCRYPT_KEY_HANDLE skey = NULL; + + jint priv_length = (*env)->GetArrayLength(env, privkey); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPRIVATE_BLOB, &skey, priv_data, priv_length, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + free(hash); + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return NULL; + } + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + + DWORD sig_len = 0; + if (NT_FAILURE(status = BCryptSignHash(skey, NULL, hash, hash_len, NULL, 0, &sig_len, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSignHash(len only)\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + free(hash); + return NULL; + } + + jbyteArray sig = (*env)->NewByteArray(env, sig_len); + jbyte *sig_data = (*env)->GetByteArrayElements(env, sig, NULL); + if (NT_FAILURE(status = BCryptSignHash(skey, NULL, hash, hash_len, sig_data, sig_len, &sig_len, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptSignHash(do)\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + free(hash); + (*env)->ReleaseByteArrayElements(env, sig, sig_data, JNI_ABORT); + return NULL; + } + (*env)->ReleaseByteArrayElements(env, sig, sig_data, 0); free(hash); - BCryptDestroyKey(skey); - BCryptCloseAlgorithmProvider(hashHandle, 0); - BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptDestroyKey(skey); + BCryptCloseAlgorithmProvider(hashHandle, 0); + BCryptCloseAlgorithmProvider(sigHandle, 0); - return sig; + return sig; } JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Mscng_verify(JNIEnv *env, jobject self, jbyteArray sig, jbyteArray data, jbyteArray pubkey, jobject params) { NTSTATUS status; - LPCWSTR hash_algo = get_sighash_algo(env, self); + LPCWSTR hash_algo = get_sighash_algo(env, self); - BCRYPT_ALG_HANDLE sigHandle = NULL; + BCRYPT_ALG_HANDLE sigHandle = NULL; if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&sigHandle, BCRYPT_ECDSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0))) { - //err - wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); - return 0; + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); + return JNI_FALSE; } - BCRYPT_ALG_HANDLE hashHandle = NULL; + BCRYPT_ALG_HANDLE hashHandle = NULL; - if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&hashHandle, hash_algo, NULL, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); - } + if (NT_FAILURE(status = BCryptOpenAlgorithmProvider(&hashHandle, hash_algo, NULL, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + return JNI_FALSE; + } - DWORD dummy = 0; - DWORD hash_len = 0; - if (NT_FAILURE(status = BCryptGetProperty(hashHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hash_len, sizeof(DWORD), &dummy, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptGetProperty(hash len)\n", status); - } + DWORD dummy = 0; + DWORD hash_len = 0; + if (NT_FAILURE(status = BCryptGetProperty(hashHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hash_len, sizeof(DWORD), &dummy, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptGetProperty(hash len)\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + return JNI_FALSE; + } PBYTE hash = calloc(hash_len, 1); - jint data_len = (*env)->GetArrayLength(env, data); - jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL); - if (NT_FAILURE(status = BCryptHash(hashHandle, NULL, 0, data_bytes, data_len, hash, hash_len))) { - wprintf(L"**** Error 0x%x returned by BCryptHash\n", status); - } - (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT); - - BCRYPT_KEY_HANDLE pkey = NULL; - - jint pub_length = (*env)->GetArrayLength(env, pubkey); - jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL); - if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) { - wprintf(L"**** Error 0x%x returned by BCryptImportKeyPair\n", status); - } - (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + jint data_len = (*env)->GetArrayLength(env, data); + jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL); + if (NT_FAILURE(status = BCryptHash(hashHandle, NULL, 0, data_bytes, data_len, hash, hash_len))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptHash\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + free(hash); + (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT); + return JNI_FALSE; + } + (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT); + + BCRYPT_KEY_HANDLE pkey = NULL; + + jint pub_length = (*env)->GetArrayLength(env, pubkey); + jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL); + if (NT_FAILURE(status = BCryptImportKeyPair(sigHandle, NULL, BCRYPT_ECCFULLPUBLIC_BLOB, &pkey, pub_data, pub_length, 0))) { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptImportKeyPair\n", status); + BCryptCloseAlgorithmProvider(sigHandle, 0); + BCryptCloseAlgorithmProvider(hashHandle, 0); + free(hash); + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + return JNI_FALSE; + } + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); - jint sig_len = (*env)->GetArrayLength(env, sig); - jbyte *sig_data = (*env)->GetByteArrayElements(env, sig, NULL); - NTSTATUS result = BCryptVerifySignature(pkey, NULL, hash, hash_len, sig_data, sig_len, 0); - (*env)->ReleaseByteArrayElements(env, sig, sig_data, JNI_ABORT); + jint sig_len = (*env)->GetArrayLength(env, sig); + jbyte *sig_data = (*env)->GetByteArrayElements(env, sig, NULL); + NTSTATUS result = BCryptVerifySignature(pkey, NULL, hash, hash_len, sig_data, sig_len, 0); + (*env)->ReleaseByteArrayElements(env, sig, sig_data, JNI_ABORT); free(hash); - BCryptDestroyKey(pkey); - BCryptCloseAlgorithmProvider(hashHandle, 0); - BCryptCloseAlgorithmProvider(sigHandle, 0); - - if (result == STATUS_SUCCESS) { - return JNI_TRUE; - } else if (result == STATUS_INVALID_SIGNATURE) { - return JNI_FALSE; - } else { - wprintf(L"**** Error 0x%x returned by BCryptVerifySignature\n", status); - return JNI_FALSE; - } + BCryptDestroyKey(pkey); + BCryptCloseAlgorithmProvider(hashHandle, 0); + BCryptCloseAlgorithmProvider(sigHandle, 0); + + if (result == STATUS_SUCCESS) { + return JNI_TRUE; + } else if (result == STATUS_INVALID_SIGNATURE) { + return JNI_FALSE; + } else { + throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptVerifySignature\n", status); + return JNI_FALSE; + } } \ No newline at end of file -- cgit v1.3.1