From 21ecc7501145b5e9b239dd5a62ccbefdcaa3a160 Mon Sep 17 00:00:00 2001 From: J08nY Date: Sun, 29 Jul 2018 17:21:04 +0200 Subject: Somewhat finished Mscng implementation. --- .gitignore | 1 + README.md | 6 +- .../crcs/ectester/standalone/libs/jni/Makefile.bat | 46 ++++++++----- .../standalone/libs/jni/NativeKeyAgreementSpi.java | 42 +++++++----- src/cz/crcs/ectester/standalone/libs/jni/mscng.c | 78 ++++++++++++++++------ src/cz/crcs/ectester/standalone/libs/jni/native.h | 2 +- 6 files changed, 118 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index f40221d..8f7585a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ /src/**/*.dll /src/**/*.exp /src/**/*.lib +/src/**/*.pdb diff --git a/README.md b/README.md index b18ebbd..2b331ff 100644 --- a/README.md +++ b/README.md @@ -239,9 +239,9 @@ API to expose and test native libraries. OpenJDK for Windows can be obtained fro Installing the Java Cryptography Extension Unlimited Strength policy files is necessary to do testing with quite a lot of practical key sizes, they are available for download: - * [Java 6](http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html) - * [Java 7](http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html) - * [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) + - [Java 6](http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html) + - [Java 7](http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html) + - [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) To install, place them in `${java.home}/jre/lib/security/`. diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat b/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat index 3530fe9..9b0d6f7 100755 --- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile.bat @@ -5,6 +5,7 @@ setlocal EnableDelayedExpansion :: - JAVA_HOME :: - CC :: - USE_EXT_MSCNG +:: - DEBUG :: See if we are cleaning. if "%1" == "clean" ( @@ -13,11 +14,13 @@ if "%1" == "clean" ( exit ) +set TAB= + :: Determine arch. -reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && (set ARCH=32& set ARCH_S=x86& set ARCH_VS=x86) || (set ARCH=64& set ARCH_S=x64& set ARCH_VS=amd64) +reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL 2>&1 && (set ARCH=32& set ARCH_S=x86& set ARCH_VS=x86) || (set ARCH=64& set ARCH_S=x64& set ARCH_VS=amd64) -echo ** ARCH %ARCH_S% +echo ** ARCH%TAB%%TAB%%ARCH_S% :: Find a working visual studio environment. @@ -27,7 +30,7 @@ set vsw_path="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" set vs_path= for /f "usebackq delims=" %%i in (`%vsw_path% -nologo -prerelease -latest -property installationPath`) do ( if exist "%%i\Common7\Tools\vsdevcmd.bat" ( - echo ** VsDevCmd at %%i\Common7\Tools\vsdevcmd.bat + echo ** VsDevCmd%TAB%%TAB%%%i\Common7\Tools\vsdevcmd.bat call "%%i\Common7\Tools\vsdevcmd.bat" -no_logo -arch=%ARCH_VS% if ERRORLEVEL 1 ( echo nope. @@ -45,7 +48,7 @@ if %found% EQU 0 ( exit /b 2 ) -echo ** VS_PATH %vs_path% +echo ** VS_PATH%TAB%%TAB%%vs_path% :: Try to find vcruntime. @@ -55,7 +58,7 @@ if exist %vc_base% ( for /f "delims=" %%i in ('dir /b /on "!vc_base!"') do ( set vc_version=%%i ) - echo ** VC_VERSION !vc_version! + echo ** VC_VERSION%TAB%!vc_version! set vc_include=%vc_base%!vc_version!\include set vc_lib=%vc_base%!vc_version!\lib\%ARCH_S% ) @@ -77,8 +80,8 @@ popd set mscng_lib_arch=%mscng_lib%\X%ARCH% -echo ** CNG_INCLUDE !mscng_include! -echo ** CNG_LIB !mscng_lib! +echo ** CNG_INCLUDE%TAB%%mscng_include% +echo ** CNG_LIB%TAB%%TAB%%mscng_lib_arch% :: Get the paths to Java JNI. @@ -92,7 +95,7 @@ if not defined JAVA_HOME ( popd ) -echo ** JAVA_HOME !JAVA_HOME! +echo ** JAVA_HOME%TAB%%JAVA_HOME% set JNI_INCLUDEDIR=%JAVA_HOME%\include set JNI_PLATFORMINCLUDEDIR=%JNI_INCLUDEDIR%\win32 @@ -104,7 +107,7 @@ if not defined CC ( set CC=cl.exe ) -echo ** CC !CC! +echo ** CC%TAB%%TAB%%CC% :: Try to find uCRT. @@ -114,7 +117,7 @@ if exist %ucrt_base% ( for /f "delims=" %%i in ('dir /b /on "!ucrt_base!\Include"') do ( set ucrt_version=%%i ) - echo ** uCRT !ucrt_version! + echo ** uCRT%TAB%%TAB%!ucrt_version! set ucrt_include=%ucrt_base%Include\!ucrt_version!\ucrt set ucrt_lib=%ucrt_base%Lib\!ucrt_version! set ucrt_lib_arch=!ucrt_lib!\ucrt\%ARCH_S% @@ -128,8 +131,8 @@ if defined USE_EXT_MSCNG ( set INCLUDE_CLI=!INCLUDE_CLI! /I"%mscng_include%" ) -echo ** INCLUDE %INCLUDE% -echo ** INCLUDE_CLI %INCLUDE_CLI% +echo ** INCLUDE%TAB%%TAB%%INCLUDE% +echo ** INCLUDE_CLI%TAB%%INCLUDE_CLI% :: Setup LIB paths. @@ -139,9 +142,22 @@ if defined USE_EXT_MSCNG ( set LIBPATH=!LIBPATH! /LIBPATH:"%mscng_lib_arch%" ) -echo ** LIB %LIB% -echo ** LIBPATH %LIBPATH% +echo ** LIB%TAB%%TAB%%LIB% +echo ** LIBPATH%TAB%%TAB%%LIBPATH% + + +:: Setup DEBUB options. +set OTHER_CLI= +if defined DEBUG ( + set OTHER_CLI=/Od /Z7 +) else ( + set OTHER_CLI=/O2 +) + +echo ** OTHER_CLI%TAB%%OTHER_CLI% echo. +echo ^>^> %CC% /W2 /EHsc %OTHER_CLI% %INCLUDE_CLI% mscng.c c_utils.c bcrypt.lib jvm.lib /Femscng_provider.dll /LD /link %LIBPATH% /nologo +echo. -%CC% /EHsc %INCLUDE_CLI% mscng.c c_utils.c bcrypt.lib jvm.lib /Femscng_provider.dll /LD /link %LIBPATH% \ No newline at end of file +%CC% /W2 /EHsc %OTHER_CLI% %INCLUDE_CLI% mscng.c c_utils.c bcrypt.lib jvm.lib /Femscng_provider.dll /LD /link %LIBPATH% /nologo \ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java index c11c803..4ed3469 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -11,6 +11,7 @@ import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECParameterSpec; +import java.security.spec.ECGenParameterSpec; /** * @author Jan Jancar johny@neuromancer.sk @@ -18,7 +19,7 @@ import java.security.spec.ECParameterSpec; public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { ECPrivateKey privateKey; ECPublicKey publicKey; - ECParameterSpec params; + AlgorithmParameterSpec params; @Override protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { @@ -30,15 +31,6 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { this.params = privateKey.getParams(); } - @Override - protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - if (!(params instanceof ECParameterSpec)) { - throw new InvalidAlgorithmParameterException(); - } - engineInit(key, random); - this.params = (ECParameterSpec) params; - } - @Override protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException { if (privateKey == null) { @@ -71,27 +63,36 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { @Override protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { - // TODO: This is dangerous/not correct ! Need to actually implement KDF1 and KDF2 here probably. + // TODO: This is dangerous/not correct ! Need to actually implement KDF1 and KDF2 here probably. Or just pass it off to the libs through some different interface. return new SecretKeySpec(engineGenerateSecret(), algorithm); } private abstract static class SimpleKeyAgreementSpi extends NativeKeyAgreementSpi { + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(params instanceof ECParameterSpec)) { + throw new InvalidAlgorithmParameterException(); + } + engineInit(key, random); + this.params = params; + } + @Override protected byte[] engineGenerateSecret() throws IllegalStateException { byte[] pubkey; if (publicKey instanceof NativeECPublicKey) { pubkey = ((NativeECPublicKey) publicKey).getData(); } else { - pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve()); + pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), ((ECParameterSpec) params).getCurve()); } byte[] privkey; if (privateKey instanceof NativeECPrivateKey) { privkey = ((NativeECPrivateKey) privateKey).getData(); } else { - privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize()); + privkey = ECUtil.toByteArray(privateKey.getS(), ((ECParameterSpec) params).getCurve().getField().getFieldSize()); } - return generateSecret(pubkey, privkey, params); + return generateSecret(pubkey, privkey, (ECParameterSpec) params); } abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); @@ -99,12 +100,21 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { private abstract static class ExtendedKeyAgreementSpi extends NativeKeyAgreementSpi { + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(params instanceof ECParameterSpec || params instanceof ECGenParameterSpec)) { + throw new InvalidAlgorithmParameterException(); + } + engineInit(key, random); + this.params = params; + } + @Override protected byte[] engineGenerateSecret() throws IllegalStateException { return generateSecret(publicKey, privateKey, params); } - abstract byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, ECParameterSpec params); + abstract byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params); } @@ -203,7 +213,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { } @Override - native byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, ECParameterSpec params); + native byte[] generateSecret(ECPublicKey pubkey, ECPrivateKey privkey, AlgorithmParameterSpec params); } public static class MscngECDHwithSHA1KDF extends Mscng { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c index a284901..16736d7 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c +++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c @@ -28,9 +28,10 @@ typedef struct { //Provider things static jclass provider_class; -#define KEYFLAG_IMPLICIT 0 -#define KEYFLAG_EXPLICIT 1 -#define KEYFLAG_NIST 2 +#define KEYFLAG_IMPLICIT 0 //Mscng native key, over named curve +#define KEYFLAG_EXPLICIT 1 //Mscng native key, over explicit ecc parameters +#define KEYFLAG_NIST 2 //Mscng native key, over NIST parameters, custom ECDH/ECDSA_P* algo +#define KEYFLAG_OTHER 3 //Other key, explicit ecc parameters 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"); @@ -797,11 +798,12 @@ static NTSTATUS init_use_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR ty } switch (keyflag) { - case 0: - case 1: + case KEYFLAG_IMPLICIT: + case KEYFLAG_EXPLICIT: + case KEYFLAG_OTHER: algo = algos[0]; break; - case 2: { + case KEYFLAG_NIST: { jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve); @@ -834,7 +836,7 @@ static NTSTATUS init_use_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR ty } switch (keyflag) { - case 0: { + case KEYFLAG_IMPLICIT: { jint meta_len = (*env)->GetArrayLength(env, meta); jbyte *meta_data = (*env)->GetByteArrayElements(env, meta, NULL); //if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_CURVE_NAME, meta_data, meta_len, 0))) { @@ -845,7 +847,8 @@ static NTSTATUS init_use_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR ty (*env)->ReleaseByteArrayElements(env, meta, meta_data, JNI_ABORT); break; } - case 1: { + case KEYFLAG_EXPLICIT: + case KEYFLAG_OTHER: { PBYTE curve; ULONG curve_len = create_curve(env, params, &curve); if (NT_FAILURE(status = BCryptSetProperty(*handle, BCRYPT_ECC_PARAMETERS, curve, curve_len, 0))) { @@ -861,15 +864,23 @@ static NTSTATUS init_use_algo(JNIEnv *env, BCRYPT_ALG_HANDLE *handle, LPCWSTR ty } static jint get_keyflag(JNIEnv *env, jobject key) { - jclass key_class = (*env)->GetObjectClass(env, key); - jmethodID get_flag = (*env)->GetMethodID(env, key_class, "getFlag", "()I"); - return (*env)->CallIntMethod(env, key, get_flag); + if ((*env)->IsInstanceOf(env, key, pubkey_class) || (*env)->IsInstanceOf(env, key, privkey_class)) { + jclass key_class = (*env)->GetObjectClass(env, key); + jmethodID get_flag = (*env)->GetMethodID(env, key_class, "getFlag", "()I"); + return (*env)->CallIntMethod(env, key, get_flag); + } else { + return KEYFLAG_OTHER; + } } static jbyteArray get_meta(JNIEnv *env, jobject key) { - jclass key_class = (*env)->GetObjectClass(env, key); - jmethodID get_meta = (*env)->GetMethodID(env, key_class, "getMeta", "()[B"); - return (jbyteArray)(*env)->CallObjectMethod(env, key, get_meta); + if ((*env)->IsInstanceOf(env, key, pubkey_class) || (*env)->IsInstanceOf(env, key, privkey_class)) { + jclass key_class = (*env)->GetObjectClass(env, key); + jmethodID get_meta = (*env)->GetMethodID(env, key_class, "getMeta", "()[B"); + return (jbyteArray)(*env)->CallObjectMethod(env, key, get_meta); + } else { + return NULL; + } } JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret(JNIEnv *env, jobject self, jobject pubkey, jobject privkey, jobject params) { @@ -897,6 +908,10 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey BCRYPT_ALG_HANDLE kaHandle = NULL; jint pub_flag = get_keyflag(env, pubkey); + if (pub_flag == KEYFLAG_OTHER) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native public key."); + return NULL; + } jbyteArray meta = get_meta(env, pubkey); if (NT_FAILURE(status = init_use_algo(env, &kaHandle, BCRYPT_ECDH_ALGORITHM, pub_flag, meta, params))) { @@ -906,27 +921,38 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey 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); + jmethodID get_data_priv = (*env)->GetMethodID(env, pubkey_class, "getData", "()[B"); + jbyteArray pubkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, pubkey, get_data_priv); + + jint pub_length = (*env)->GetArrayLength(env, pubkey_barray); + jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey_barray, 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); + (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT); return NULL; } - (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, pubkey_barray, pub_data, JNI_ABORT); jint priv_flag = get_keyflag(env, privkey); - jint priv_length = (*env)->GetArrayLength(env, privkey); - jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + if (priv_flag == KEYFLAG_OTHER) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native private key."); + return NULL; + } + + jmethodID get_data_pub = (*env)->GetMethodID(env, privkey_class, "getData", "()[B"); + jbyteArray privkey_barray = (jbyteArray)(*env)->CallObjectMethod(env, privkey, get_data_pub); + + jint priv_length = (*env)->GetArrayLength(env, privkey_barray); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey_barray, 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); + (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT); return NULL; } - (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, privkey_barray, priv_data, JNI_ABORT); BCRYPT_SECRET_HANDLE ka = NULL; @@ -1002,6 +1028,10 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig BCRYPT_ALG_HANDLE sigHandle = NULL; jint keyflag = get_keyflag(env, privkey); + if (keyflag == KEYFLAG_OTHER) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native private key."); + return NULL; + } jbyteArray meta = get_meta(env, privkey); if (NT_FAILURE(status = init_use_algo(env, &sigHandle, BCRYPT_ECDSA_ALGORITHM, keyflag, meta, params))) { @@ -1099,6 +1129,10 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna BCRYPT_ALG_HANDLE sigHandle = NULL; jint keyflag = get_keyflag(env, pubkey); + if (keyflag == KEYFLAG_OTHER) { // TODO: This is not necessary + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Cannot import non-native public key."); + return JNI_FALSE; + } jbyteArray meta = get_meta(env, pubkey); if (NT_FAILURE(status = init_use_algo(env, &sigHandle, BCRYPT_ECDSA_ALGORITHM, keyflag, meta, params))) { diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h index b5cde43..dcdaa1b 100644 --- a/src/cz/crcs/ectester/standalone/libs/jni/native.h +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -819,7 +819,7 @@ extern "C" { /* * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Mscng * Method: generateSecret - * Signature: (Ljava/security/interfaces/ECPublicKey;Ljava/security/interfaces/ECPrivateKey;Ljava/security/spec/ECParameterSpec;)[B + * Signature: (Ljava/security/interfaces/ECPublicKey;Ljava/security/interfaces/ECPrivateKey;Ljava/security/spec/AlgorithmParameterSpec;)[B */ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Mscng_generateSecret (JNIEnv *, jobject, jobject, jobject, jobject); -- cgit v1.2.3-70-g09d2