diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/CMakeLists.txt b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/CMakeLists.txt index f7075190a1504..b0b7f83cbf838 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/CMakeLists.txt @@ -2,10 +2,14 @@ project(System.Security.Cryptography.Native.Android C) add_compile_options(-Wno-gnu-zero-variadic-macro-arguments) add_compile_options(-Wno-unused-parameter) -add_compile_options(-Wno-unused-variable) set(NATIVECRYPTO_SOURCES - android_security.c + pal_jni.c + pal_misc.c + pal_evp.c + pal_evp_cipher.c + pal_hmac.c + pal_bignum.c ) add_library(System.Security.Cryptography.Native.Android diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/android_security.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/android_security.c deleted file mode 100644 index b74604747b3e0..0000000000000 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/android_security.c +++ /dev/null @@ -1,576 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_types.h" -#include "pal_utilities.h" -#include "pal_safecrt.h" - -#include "android_security.h" - -#include -#include -#include -#include -#include -#include - -static JavaVM *gJvm; - -#define LOG_DEBUG(fmt, ...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "DOTNET", "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)) -#define LOG_INFO(fmt, ...) ((void)__android_log_print(ANDROID_LOG_INFO, "DOTNET", "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)) -#define LOG_ERROR(fmt, ...) ((void)__android_log_print(ANDROID_LOG_ERROR, "DOTNET", "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)) - -// java/security/SecureRandom -static jclass g_randClass = NULL; -static jmethodID g_randCtor = NULL; -static jmethodID g_randNextBytesMethod = NULL; - -// java/security/MessageDigest -static jclass g_mdClass = NULL; -static jmethodID g_mdGetInstanceMethod = NULL; -static jmethodID g_mdDigestMethod = NULL; -static jmethodID g_mdDigestCurrentMethodId = NULL; -static jmethodID g_mdResetMethod = NULL; -static jmethodID g_mdUpdateMethod = NULL; - -// javax/crypto/Mac -static jclass g_macClass = NULL; -static jmethodID g_macGetInstanceMethod = NULL; -static jmethodID g_macDoFinalMethod = NULL; -static jmethodID g_macUpdateMethod = NULL; -static jmethodID g_macInitMethod = NULL; -static jmethodID g_macResetMethod = NULL; - -// javax/crypto/spec/SecretKeySpec -static jclass g_sksClass = NULL; -static jmethodID g_sksCtor = NULL; - -// javax/crypto/Cipher -static jclass g_cipherClass = NULL; -static jmethodID g_cipherGetInstanceMethod = NULL; -static jmethodID g_cipherDoFinalMethod = NULL; -static jmethodID g_cipherUpdateMethod = NULL; -static jmethodID g_cipherInitMethod = NULL; -static jmethodID g_getBlockSizeMethod = NULL; - -// javax/crypto/spec/IvParameterSpec -static jclass g_ivPsClass = NULL; -static jmethodID g_ivPsCtor = NULL; - -static jobject ToGRef(JNIEnv *env, jobject lref) -{ - if (!lref) - return NULL; - jobject gref = (*env)->NewGlobalRef(env, lref); - (*env)->DeleteLocalRef(env, lref); - return gref; -} - -static void ReleaseGRef(JNIEnv *env, jobject gref) -{ - if (gref) - (*env)->DeleteGlobalRef(env, gref); -} - -static jclass GetClassGRef(JNIEnv *env, const char* name) -{ - LOG_DEBUG("Finding %s class", name); - jclass klass = ToGRef(env, (*env)->FindClass (env, name)); - if (!klass) { - LOG_ERROR("class %s was not found", name); - assert(klass); - } - return klass; -} - -static bool CheckJNIExceptions(JNIEnv* env) -{ - if ((*env)->ExceptionCheck(env)) - { - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - return true; - } - return false; -} - -static jmethodID GetMethod(JNIEnv *env, bool isStatic, jclass klass, const char* name, const char* sig) -{ - LOG_DEBUG("Finding %s method", name); - jmethodID mid = isStatic ? (*env)->GetStaticMethodID(env, klass, name, sig) : (*env)->GetMethodID(env, klass, name, sig); - if (!mid) { - LOG_ERROR("method %s %s was not found", name, sig); - assert(mid); - } - return mid; -} - -static JNIEnv* GetJniEnv() -{ - JNIEnv *env; - (*gJvm)->GetEnv(gJvm, (void**)&env, JNI_VERSION_1_6); - if (env) - return env; - jint ret = (*gJvm)->AttachCurrentThreadAsDaemon(gJvm, &env, NULL); - assert(ret == JNI_OK && "Unable to attach thread to JVM"); - return env; -} - -PALEXPORT JNIEXPORT jint JNICALL -JNI_OnLoad(JavaVM *vm, void *reserved) -{ - (void)reserved; - LOG_INFO("JNI_OnLoad in android_security.c"); - gJvm = vm; - - JNIEnv* env = GetJniEnv(); - - // cache some classes and methods while we're in the thread-safe JNI_OnLoad - g_randClass = GetClassGRef(env, "java/security/SecureRandom"); - g_randCtor = GetMethod(env, false, g_randClass, "", "()V"); - g_randNextBytesMethod = GetMethod(env, false, g_randClass, "nextBytes", "([B)V"); - - g_mdClass = GetClassGRef(env, "java/security/MessageDigest"); - g_mdGetInstanceMethod = GetMethod(env, true, g_mdClass, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;"); - g_mdResetMethod = GetMethod(env, false, g_mdClass, "reset", "()V"); - g_mdDigestMethod = GetMethod(env, false, g_mdClass, "digest", "([B)[B"); - g_mdDigestCurrentMethodId = GetMethod(env, false, g_mdClass, "digest", "()[B"); - g_mdUpdateMethod = GetMethod(env, false, g_mdClass, "update", "([B)V"); - - g_macClass = GetClassGRef(env, "javax/crypto/Mac"); - g_macGetInstanceMethod = GetMethod(env, true, g_macClass, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Mac;"); - g_macDoFinalMethod = GetMethod(env, false, g_macClass, "doFinal", "()[B"); - g_macUpdateMethod = GetMethod(env, false, g_macClass, "update", "([B)V"); - g_macInitMethod = GetMethod(env, false, g_macClass, "init", "(Ljava/security/Key;)V"); - g_macResetMethod = GetMethod(env, false, g_macClass, "reset", "()V"); - - g_sksClass = GetClassGRef(env, "javax/crypto/spec/SecretKeySpec"); - g_sksCtor = GetMethod(env, false, g_sksClass, "", "([BLjava/lang/String;)V"); - - g_cipherClass = GetClassGRef(env, "javax/crypto/Cipher"); - g_cipherGetInstanceMethod = GetMethod(env, true, g_cipherClass, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Cipher;"); - g_getBlockSizeMethod = GetMethod(env, false, g_cipherClass, "getBlockSize", "()I"); - g_cipherDoFinalMethod = GetMethod(env, false, g_cipherClass, "doFinal", "([BI)I"); - g_cipherUpdateMethod = GetMethod(env, false, g_cipherClass, "update", "([B)[B"); - g_cipherInitMethod = GetMethod(env, false, g_cipherClass, "init", "(ILjava/security/Key;Ljava/security/spec/AlgorithmParameterSpec;)V"); - - g_ivPsClass = GetClassGRef(env, "javax/crypto/spec/IvParameterSpec"); - g_ivPsCtor = GetMethod(env, false, g_ivPsClass, "", "([B)V"); - - return JNI_VERSION_1_6; -} - -int32_t CryptoNative_EnsureOpenSslInitialized(void) -{ - return 0; -} - -int32_t CryptoNative_GetRandomBytes(uint8_t* buff, int32_t len) -{ - JNIEnv* env = GetJniEnv(); - jobject randObj = (*env)->NewObject(env, g_randClass, g_randCtor); - assert(randObj && "Unable to create an instance of java/security/SecureRandom"); - - jbyteArray buffArray = (*env)->NewByteArray(env, len); - (*env)->SetByteArrayRegion(env, buffArray, 0, len, (jbyte*)buff); - (*env)->CallVoidMethod(env, randObj, g_randNextBytesMethod, buffArray); - (*env)->GetByteArrayRegion(env, buffArray, 0, len, (jbyte*)buff); - - (*env)->DeleteLocalRef(env, buffArray); - (*env)->DeleteLocalRef(env, randObj); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -// just some unique numbers -intptr_t CryptoNative_EvpMd5() { return 101; } -intptr_t CryptoNative_EvpSha1() { return 102; } -intptr_t CryptoNative_EvpSha256() { return 103; } -intptr_t CryptoNative_EvpSha384() { return 104; } -intptr_t CryptoNative_EvpSha512() { return 105; } -intptr_t CryptoNative_EvpAes128Ecb() { return 1001; } -intptr_t CryptoNative_EvpAes128Cbc() { return 1002; } -intptr_t CryptoNative_EvpAes128Cfb8() { return 1003; } -intptr_t CryptoNative_EvpAes128Cfb128() { return 1004; } -intptr_t CryptoNative_EvpAes128Gcm() { return 1005; } -intptr_t CryptoNative_EvpAes128Ccm() { return 1006; } -intptr_t CryptoNative_EvpAes192Ecb() { return 1007; } -intptr_t CryptoNative_EvpAes192Cbc() { return 1008; } -intptr_t CryptoNative_EvpAes192Cfb8() { return 1009; } -intptr_t CryptoNative_EvpAes192Cfb128() { return 1010; } -intptr_t CryptoNative_EvpAes192Gcm() { return 1011; } -intptr_t CryptoNative_EvpAes192Ccm() { return 1012; } -intptr_t CryptoNative_EvpAes256Ecb() { return 1013; } -intptr_t CryptoNative_EvpAes256Cbc() { return 1014; } -intptr_t CryptoNative_EvpAes256Cfb8() { return 1015; } -intptr_t CryptoNative_EvpAes256Cfb128() { return 1016; } -intptr_t CryptoNative_EvpAes256Gcm() { return 1017; } -intptr_t CryptoNative_EvpAes256Ccm() { return 1018; } -intptr_t CryptoNative_EvpDes3Ecb() { return 1019; } -intptr_t CryptoNative_EvpDes3Cbc() { return 1020; } -intptr_t CryptoNative_EvpDes3Cfb8() { return 1021; } -intptr_t CryptoNative_EvpDes3Cfb64() { return 1022; } -intptr_t CryptoNative_EvpDesEcb() { return 1023; } -intptr_t CryptoNative_EvpDesCfb8() { return 1024; } -intptr_t CryptoNative_EvpDesCbc() { return 1025; } -intptr_t CryptoNative_EvpRC2Ecb() { return 1026; } -intptr_t CryptoNative_EvpRC2Cbc() { return 1027; } - -int32_t CryptoNative_EvpMdSize(intptr_t md) -{ - if (md == CryptoNative_EvpSha1()) return 20; - if (md == CryptoNative_EvpSha256()) return 32; - if (md == CryptoNative_EvpSha384()) return 48; - if (md == CryptoNative_EvpSha512()) return 64; - if (md == CryptoNative_EvpMd5()) return 16; - assert(0 && "unexpected type"); - return -1; -} - -int32_t CryptoNative_GetMaxMdSize() -{ - return EVP_MAX_MD_SIZE; -} - -static jobject GetMessageDigestInstance(JNIEnv* env, intptr_t type) -{ - jobject mdName = NULL; - if (type == CryptoNative_EvpSha1()) - mdName = (*env)->NewStringUTF(env, "SHA-1"); - else if (type == CryptoNative_EvpSha256()) - mdName = (*env)->NewStringUTF(env, "SHA-256"); - else if (type == CryptoNative_EvpSha384()) - mdName = (*env)->NewStringUTF(env, "SHA-384"); - else if (type == CryptoNative_EvpSha512()) - mdName = (*env)->NewStringUTF(env, "SHA-512"); - else if (type == CryptoNative_EvpMd5()) - mdName = (*env)->NewStringUTF(env, "MD5"); - else - return NULL; - - jobject mdObj = (*env)->CallStaticObjectMethod(env, g_mdClass, g_mdGetInstanceMethod, mdName); - (*env)->DeleteLocalRef(env, mdName); - - return CheckJNIExceptions(env) ? FAIL : mdObj; -} - -int32_t CryptoNative_EvpDigestOneShot(intptr_t type, void* source, int32_t sourceSize, uint8_t* md, uint32_t* mdSize) -{ - if (!type || !md || !mdSize || sourceSize < 0) - return FAIL; - - JNIEnv* env = GetJniEnv(); - - jobject mdObj = GetMessageDigestInstance(env, type); - if (!mdObj) - return FAIL; - - jbyteArray bytes = (*env)->NewByteArray(env, sourceSize); - (*env)->SetByteArrayRegion(env, bytes, 0, sourceSize, (jbyte*) source); - jbyteArray hashedBytes = (jbyteArray)(*env)->CallObjectMethod(env, mdObj, g_mdDigestMethod, bytes); - assert(hashedBytes && "MessageDigest.digest(...) was not expected to return null"); - - jsize hashedBytesLen = (*env)->GetArrayLength(env, hashedBytes); - (*env)->GetByteArrayRegion(env, hashedBytes, 0, hashedBytesLen, (jbyte*) md); - *mdSize = (uint32_t)hashedBytesLen; - - (*env)->DeleteLocalRef(env, bytes); - (*env)->DeleteLocalRef(env, hashedBytes); - (*env)->DeleteLocalRef(env, mdObj); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -void* CryptoNative_EvpMdCtxCreate(intptr_t type) -{ - JNIEnv* env = GetJniEnv(); - return (void*)ToGRef(env, GetMessageDigestInstance(env, type)); -} - -int32_t CryptoNative_EvpDigestReset(void* ctx, intptr_t type) -{ - if (!ctx) - return FAIL; - - (void)type; // not used - - JNIEnv* env = GetJniEnv(); - jobject mdObj = (jobject)ctx; - (*env)->CallVoidMethod(env, mdObj, g_mdResetMethod); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -int32_t CryptoNative_EvpDigestUpdate(void* ctx, void* d, int32_t cnt) -{ - if (!ctx) - return FAIL; - - JNIEnv* env = GetJniEnv(); - jobject mdObj = (jobject)ctx; - - jbyteArray bytes = (*env)->NewByteArray(env, cnt); - (*env)->SetByteArrayRegion(env, bytes, 0, cnt, (jbyte*) d); - (*env)->CallVoidMethod(env, mdObj, g_mdUpdateMethod, bytes); - (*env)->DeleteLocalRef(env, bytes); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -int32_t CryptoNative_EvpDigestFinalEx(void* ctx, uint8_t* md, uint32_t* s) -{ - return CryptoNative_EvpDigestCurrent(ctx, md, s); -} - -int32_t CryptoNative_EvpDigestCurrent(void* ctx, uint8_t* md, uint32_t* s) -{ - if (!ctx) - return FAIL; - - JNIEnv* env = GetJniEnv(); - jobject mdObj = (jobject)ctx; - - jbyteArray bytes = (jbyteArray)(*env)->CallObjectMethod(env, mdObj, g_mdDigestCurrentMethodId); - assert(bytes && "digest() was not expected to return null"); - jsize bytesLen = (*env)->GetArrayLength(env, bytes); - *s = (uint32_t)bytesLen; - (*env)->GetByteArrayRegion(env, bytes, 0, bytesLen, (jbyte*) md); - (*env)->DeleteLocalRef(env, bytes); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -void CryptoNative_EvpMdCtxDestroy(void* ctx) -{ - ReleaseGRef(GetJniEnv(), (jobject)ctx); -} - -void* CryptoNative_HmacCreate(uint8_t* key, int32_t keyLen, intptr_t type) -{ - assert(key || (keyLen == 0)); - assert(keyLen >= 0); - - // Mac mac = Mac.getInstance(algName); - // SecretKeySpec key = new SecretKeySpec(key, algName); - // mac.init(key); - - JNIEnv* env = GetJniEnv(); - - jstring macName = NULL; - if (type == CryptoNative_EvpSha1()) - macName = (jstring)(*env)->NewStringUTF(env, "HmacSHA1"); - else if (type == CryptoNative_EvpSha256()) - macName = (jstring)(*env)->NewStringUTF(env, "HmacSHA256"); - else if (type == CryptoNative_EvpSha384()) - macName = (jstring)(*env)->NewStringUTF(env, "HmacSHA384"); - else if (type == CryptoNative_EvpSha512()) - macName = (jstring)(*env)->NewStringUTF(env, "HmacSHA512"); - else if (type == CryptoNative_EvpMd5()) - macName = (jstring)(*env)->NewStringUTF(env, "HmacMD5"); - else - return FAIL; - - jbyteArray keyBytes = (*env)->NewByteArray(env, keyLen); - (*env)->SetByteArrayRegion(env, keyBytes, 0, keyLen, (jbyte*)key); - jobject sksObj = (*env)->NewObject(env, g_sksClass, g_sksCtor, keyBytes, macName); - assert(sksObj && "Unable to create an instance of SecretKeySpec"); - jobject macObj = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_macClass, g_macGetInstanceMethod, macName)); - (*env)->CallVoidMethod(env, macObj, g_macInitMethod, sksObj); - (*env)->DeleteLocalRef(env, keyBytes); - (*env)->DeleteLocalRef(env, sksObj); - (*env)->DeleteLocalRef(env, macName); - - return CheckJNIExceptions(env) ? FAIL : macObj; -} - -int32_t CryptoNative_HmacReset(void* ctx) -{ - if (!ctx) - return FAIL; - - JNIEnv* env = GetJniEnv(); - jobject macObj = (jobject)ctx; - (*env)->CallVoidMethod(env, macObj, g_macResetMethod); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -int32_t CryptoNative_HmacUpdate(void* ctx, uint8_t* data, int32_t len) -{ - if (!ctx) - return FAIL; - - JNIEnv* env = GetJniEnv(); - jobject macObj = (jobject)ctx; - jbyteArray dataBytes = (*env)->NewByteArray(env, len); - (*env)->SetByteArrayRegion(env, dataBytes, 0, len, (jbyte*)data); - (*env)->CallVoidMethod(env, macObj, g_macUpdateMethod, dataBytes); - (*env)->DeleteLocalRef(env, dataBytes); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -int32_t CryptoNative_HmacFinal(void* ctx, uint8_t* data, int32_t* len) -{ - return CryptoNative_HmacCurrent(ctx, data, len); -} - -int32_t CryptoNative_HmacCurrent(void* ctx, uint8_t* data, int32_t* len) -{ - if (!ctx) - return FAIL; - - JNIEnv* env = GetJniEnv(); - jobject macObj = (jobject)ctx; - jbyteArray dataBytes = (jbyteArray)(*env)->CallObjectMethod(env, macObj, g_macDoFinalMethod); - jsize dataBytesLen = (*env)->GetArrayLength(env, dataBytes); - *len = (int32_t)dataBytesLen; - (*env)->GetByteArrayRegion(env, dataBytes, 0, dataBytesLen, (jbyte*) data); - (*env)->DeleteLocalRef(env, dataBytes); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -void CryptoNative_HmacDestroy(void* ctx) -{ - ReleaseGRef(GetJniEnv(), (jobject)ctx); -} - -// TODO: AES/DES - -void* CryptoNative_EvpCipherCreate2(intptr_t type, uint8_t* key, int32_t keyLength, int32_t effectiveKeyLength, uint8_t* iv, int32_t enc) -{ - if (effectiveKeyLength != 0) - { - LOG_ERROR("Non-zero effectiveKeyLength is not supported"); - return FAIL; - } - - // input: 0 for Decrypt, 1 for Encrypt - // Cipher: 2 for Decrypt, 1 for Encrypt - assert(enc == 0 || enc == 1); - int encMode = enc == 0 ? 2 : 1; - - JNIEnv* env = GetJniEnv(); - // Cipher cipher = Cipher.getInstance("AES"); - // int ivSize = cipher.getBlockSize(); - // SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES"); - // IvParameterSpec ivSpec = new IvParameterSpec(IV); - // cipher.init(encMode, keySpec, ivSpec); - - jobject algName = NULL; - - if ((type == CryptoNative_EvpAes128Cbc()) || - (type == CryptoNative_EvpAes192Cbc()) || - (type == CryptoNative_EvpAes256Cbc())) - { - algName = (*env)->NewStringUTF(env, "AES/CBC/NoPadding"); - } - else if ( - (type == CryptoNative_EvpAes128Ecb()) || - (type == CryptoNative_EvpAes192Ecb()) || - (type == CryptoNative_EvpAes256Ecb())) - { - algName = (*env)->NewStringUTF(env, "AES/ECB/NoPadding"); - } - else if ( - (type == CryptoNative_EvpAes128Cfb8()) || - (type == CryptoNative_EvpAes192Cfb8()) || - (type == CryptoNative_EvpAes256Cfb8())) - { - algName = (*env)->NewStringUTF(env, "AES/CFB/NoPadding"); - } - else - { - LOG_ERROR("unexpected type: %d", (int)type); - return FAIL; - } - - jobject cipherObj = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_cipherClass, g_cipherGetInstanceMethod, algName)); - - int blockSize = (*env)->CallIntMethod(env, cipherObj, g_getBlockSizeMethod); - jbyteArray keyBytes = (*env)->NewByteArray(env, keyLength / 8); // bits to bytes, e.g. 256 -> 32 - (*env)->SetByteArrayRegion(env, keyBytes, 0, keyLength / 8, (jbyte*)key); - jbyteArray ivBytes = (*env)->NewByteArray(env, blockSize); - (*env)->SetByteArrayRegion(env, ivBytes, 0, blockSize, (jbyte*)iv); - - jobject sksObj = (*env)->NewObject(env, g_sksClass, g_sksCtor, keyBytes, algName); - jobject ivPsObj = (*env)->NewObject(env, g_ivPsClass, g_ivPsCtor, ivBytes); - (*env)->CallVoidMethod(env, cipherObj, g_cipherInitMethod, encMode, sksObj, ivPsObj); - - (*env)->DeleteLocalRef(env, algName); - (*env)->DeleteLocalRef(env, sksObj); - (*env)->DeleteLocalRef(env, ivPsObj); - (*env)->DeleteLocalRef(env, keyBytes); - (*env)->DeleteLocalRef(env, ivBytes); - - return CheckJNIExceptions(env) ? FAIL : cipherObj; -} - - -int32_t CryptoNative_EvpCipherUpdate(void* ctx, uint8_t* outm, int32_t* outl, uint8_t* in, int32_t inl) -{ - if (!ctx) - return FAIL; - - JNIEnv* env = GetJniEnv(); - jobject cipherObj = (jobject)ctx; - jbyteArray inDataBytes = (*env)->NewByteArray(env, inl); - (*env)->SetByteArrayRegion(env, inDataBytes, 0, inl, (jbyte*)in); - jbyteArray outDataBytes = (jbyteArray)(*env)->CallObjectMethod(env, cipherObj, g_cipherUpdateMethod, inDataBytes); - if (outDataBytes) { - jsize outDataBytesLen = (*env)->GetArrayLength(env, outDataBytes); - *outl = (int32_t)outDataBytesLen; - (*env)->GetByteArrayRegion(env, outDataBytes, 0, outDataBytesLen, (jbyte*) outm); - (*env)->DeleteLocalRef(env, outDataBytes); - } else { - *outl = 0; - } - - (*env)->DeleteLocalRef(env, inDataBytes); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -int32_t CryptoNative_EvpCipherFinalEx(void* ctx, uint8_t* outm, int32_t* outl) -{ - if (!ctx) - return FAIL; - - JNIEnv* env = GetJniEnv(); - jobject cipherObj = (jobject)ctx; - - int blockSize = (*env)->CallIntMethod(env, cipherObj, g_getBlockSizeMethod); - jbyteArray outBytes = (*env)->NewByteArray(env, blockSize); - int written = (*env)->CallIntMethod(env, cipherObj, g_cipherDoFinalMethod, outBytes, 0 /*offset*/); - if (written > 0) - (*env)->GetByteArrayRegion(env, outBytes, 0, blockSize, (jbyte*) outm); - *outl = written; - (*env)->DeleteLocalRef(env, outBytes); - - return CheckJNIExceptions(env) ? FAIL : SUCCESS; -} - -int32_t CryptoNative_EvpCipherCtxSetPadding(void* x, int32_t padding) -{ - if (padding == 0) - { - return SUCCESS; - } - else - { - LOG_ERROR("Non-zero padding (%d) is not supported", (int)padding); - return FAIL; - } -} - -int32_t CryptoNative_EvpCipherReset(void* ctx) -{ - // there is no "reset()" API for an existing Cipher object - return SUCCESS; -} - -void CryptoNative_EvpCipherDestroy(void* ctx) -{ - ReleaseGRef(GetJniEnv(), (jobject)ctx); -} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/android_security.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/android_security.h deleted file mode 100644 index cd773560de665..0000000000000 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/android_security.h +++ /dev/null @@ -1,79 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// - -#pragma once - -#include "pal_compiler.h" - -#define FAIL 0 -#define SUCCESS 1 -#define EVP_MAX_MD_SIZE 64 - -PALEXPORT int32_t CryptoNative_EnsureOpenSslInitialized(void); - -PALEXPORT int32_t CryptoNative_GetRandomBytes(uint8_t* buf, int32_t num); -PALEXPORT int32_t CryptoNative_EvpMdSize(intptr_t md); -PALEXPORT intptr_t CryptoNative_EvpMd5(void); -PALEXPORT intptr_t CryptoNative_EvpSha1(void); -PALEXPORT intptr_t CryptoNative_EvpSha256(void); -PALEXPORT intptr_t CryptoNative_EvpSha384(void); -PALEXPORT intptr_t CryptoNative_EvpSha512(void); -PALEXPORT int32_t CryptoNative_GetMaxMdSize(void); -PALEXPORT int32_t CryptoNative_EvpDigestOneShot(intptr_t type, void* source, int32_t sourceSize, uint8_t* md, uint32_t* mdSize); - -PALEXPORT void* CryptoNative_EvpMdCtxCreate(intptr_t type); -PALEXPORT int32_t CryptoNative_EvpDigestReset(void* ctx, intptr_t type); -PALEXPORT int32_t CryptoNative_EvpDigestUpdate(void* ctx, void* d, int32_t cnt); -PALEXPORT int32_t CryptoNative_EvpDigestFinalEx(void* ctx, uint8_t* md, uint32_t* s); -PALEXPORT int32_t CryptoNative_EvpDigestCurrent(void* ctx, uint8_t* md, uint32_t* s); -PALEXPORT void CryptoNative_EvpMdCtxDestroy(void* ctx); - -PALEXPORT void* CryptoNative_HmacCreate(uint8_t* key, int32_t keyLen, intptr_t md); -PALEXPORT int32_t CryptoNative_HmacReset(void* ctx); -PALEXPORT int32_t CryptoNative_HmacUpdate(void* ctx, uint8_t* data, int32_t len); -PALEXPORT int32_t CryptoNative_HmacFinal(void* ctx, uint8_t* md, int32_t* len); -PALEXPORT int32_t CryptoNative_HmacCurrent(void* ctx, uint8_t* md, int32_t* len); -PALEXPORT void CryptoNative_HmacDestroy(void* ctx); - -PALEXPORT void* CryptoNative_EvpCipherCreate2(intptr_t type, uint8_t* key, int32_t keyLength, int32_t effectiveKeyLength, uint8_t* iv, int32_t enc); -PALEXPORT void* CryptoNative_EvpCipherCreatePartial(intptr_t type); -PALEXPORT int32_t CryptoNative_EvpCipherSetKeyAndIV(void* ctx, uint8_t* key, uint8_t* iv, int32_t enc); -PALEXPORT int32_t CryptoNative_EvpCipherSetGcmNonceLength(void* ctx, int32_t ivLength); -PALEXPORT int32_t CryptoNative_EvpCipherSetCcmNonceLength(void* ctx, int32_t ivLength); -PALEXPORT void CryptoNative_EvpCipherDestroy(void* ctx); -PALEXPORT int32_t CryptoNative_EvpCipherReset(void* ctx); -PALEXPORT int32_t CryptoNative_EvpCipherCtxSetPadding(void* x, int32_t padding); -PALEXPORT int32_t CryptoNative_EvpCipherUpdate(void* ctx, uint8_t* out, int32_t* outl, uint8_t* in, int32_t inl); -PALEXPORT int32_t CryptoNative_EvpCipherFinalEx(void* ctx, uint8_t* outm, int32_t* outl); -PALEXPORT int32_t CryptoNative_EvpCipherGetGcmTag(void* ctx, uint8_t* tag, int32_t tagLength); -PALEXPORT int32_t CryptoNative_EvpCipherSetGcmTag(void* ctx, uint8_t* tag, int32_t tagLength); -PALEXPORT int32_t CryptoNative_EvpCipherGetCcmTag(void* ctx, uint8_t* tag, int32_t tagLength); -PALEXPORT int32_t CryptoNative_EvpCipherSetCcmTag(void* ctx, uint8_t* tag, int32_t tagLength); -PALEXPORT intptr_t CryptoNative_EvpAes128Ecb(void); -PALEXPORT intptr_t CryptoNative_EvpAes128Cbc(void); -PALEXPORT intptr_t CryptoNative_EvpAes128Cfb8(void); -PALEXPORT intptr_t CryptoNative_EvpAes128Cfb128(void); -PALEXPORT intptr_t CryptoNative_EvpAes128Gcm(void); -PALEXPORT intptr_t CryptoNative_EvpAes128Ccm(void); -PALEXPORT intptr_t CryptoNative_EvpAes192Ecb(void); -PALEXPORT intptr_t CryptoNative_EvpAes192Cbc(void); -PALEXPORT intptr_t CryptoNative_EvpAes192Cfb8(void); -PALEXPORT intptr_t CryptoNative_EvpAes192Cfb128(void); -PALEXPORT intptr_t CryptoNative_EvpAes192Gcm(void); -PALEXPORT intptr_t CryptoNative_EvpAes192Ccm(void); -PALEXPORT intptr_t CryptoNative_EvpAes256Ecb(void); -PALEXPORT intptr_t CryptoNative_EvpAes256Cbc(void); -PALEXPORT intptr_t CryptoNative_EvpAes256Cfb8(void); -PALEXPORT intptr_t CryptoNative_EvpAes256Cfb128(void); -PALEXPORT intptr_t CryptoNative_EvpAes256Gcm(void); -PALEXPORT intptr_t CryptoNative_EvpAes256Ccm(void); -PALEXPORT intptr_t CryptoNative_EvpDes3Ecb(void); -PALEXPORT intptr_t CryptoNative_EvpDes3Cbc(void); -PALEXPORT intptr_t CryptoNative_EvpDes3Cfb8(void); -PALEXPORT intptr_t CryptoNative_EvpDes3Cfb64(void); -PALEXPORT intptr_t CryptoNative_EvpDesEcb(void); -PALEXPORT intptr_t CryptoNative_EvpDesCfb8(void); -PALEXPORT intptr_t CryptoNative_EvpDesCbc(void); -PALEXPORT intptr_t CryptoNative_EvpRC2Ecb(void); -PALEXPORT intptr_t CryptoNative_EvpRC2Cbc(void); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_bignum.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_bignum.c new file mode 100644 index 0000000000000..4aa0463fdee06 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_bignum.c @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_bignum.h" + +jobject CryptoNative_BigNumFromBinary(uint8_t* bytes, int32_t len) +{ + // return new BigInteger(bytes) + JNIEnv* env = GetJNIEnv(); + jbyteArray buffArray = (*env)->NewByteArray(env, len); + (*env)->SetByteArrayRegion(env, buffArray, 0, len, (jbyte*)bytes); + jobject bigNum = (*env)->NewObject(env, g_bigNumClass, g_bigNumCtor, buffArray); + (*env)->DeleteLocalRef(env, buffArray); + return CheckJNIExceptions(env) ? FAIL : bigNum; +} + +int32_t CryptoNative_BigNumToBinary(jobject bignum, uint8_t* output) +{ + // bigNum.toByteArray() + JNIEnv* env = GetJNIEnv(); + jbyteArray bytes = (jbyteArray)(*env)->CallObjectMethod(env, bignum, g_toByteArrayMethod); + jsize bytesLen = (*env)->GetArrayLength(env, bytes); + (*env)->GetByteArrayRegion(env, bytes, 0, bytesLen, (jbyte*)output); + (*env)->DeleteLocalRef(env, bytes); + return CheckJNIExceptions(env) ? FAIL : (int32_t)bytesLen; +} + +int32_t CryptoNative_GetBigNumBytes(jobject bignum) +{ + // bigNum.toByteArray().length(); + JNIEnv* env = GetJNIEnv(); + jbyteArray bytes = (jbyteArray)(*env)->CallObjectMethod(env, bignum, g_toByteArrayMethod); + jsize bytesLen = (*env)->GetArrayLength(env, bytes); + (*env)->DeleteLocalRef(env, bytes); + return CheckJNIExceptions(env) ? FAIL : (int32_t)bytesLen; +} + +void CryptoNative_BigNumDestroy(jobject bignum) +{ + ReleaseGRef(GetJNIEnv(), bignum); +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_bignum.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_bignum.h new file mode 100644 index 0000000000000..20552ad004b9e --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_bignum.h @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "pal_jni.h" + +PALEXPORT void CryptoNative_BigNumDestroy(jobject bignum); +PALEXPORT jobject CryptoNative_BigNumFromBinary(uint8_t* bytes, int32_t len); +PALEXPORT int32_t CryptoNative_BigNumToBinary(jobject bignum, uint8_t* output); +PALEXPORT int32_t CryptoNative_GetBigNumBytes(jobject bignum); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp.c new file mode 100644 index 0000000000000..fe7b721654941 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp.c @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_evp.h" + +// just some unique IDs +intptr_t CryptoNative_EvpMd5() { return 101; } +intptr_t CryptoNative_EvpSha1() { return 102; } +intptr_t CryptoNative_EvpSha256() { return 103; } +intptr_t CryptoNative_EvpSha384() { return 104; } +intptr_t CryptoNative_EvpSha512() { return 105; } + +int32_t CryptoNative_EvpMdSize(intptr_t md) +{ + if (md == CryptoNative_EvpSha1()) return 20; + if (md == CryptoNative_EvpSha256()) return 32; + if (md == CryptoNative_EvpSha384()) return 48; + if (md == CryptoNative_EvpSha512()) return 64; + if (md == CryptoNative_EvpMd5()) return 16; + assert(0 && "unexpected type"); + return -1; +} + +int32_t CryptoNative_GetMaxMdSize() +{ + return EVP_MAX_MD_SIZE; +} + +static jobject GetMessageDigestInstance(JNIEnv* env, intptr_t type) +{ + jobject mdName = NULL; + if (type == CryptoNative_EvpSha1()) + mdName = JSTRING("SHA-1"); + else if (type == CryptoNative_EvpSha256()) + mdName = JSTRING("SHA-256"); + else if (type == CryptoNative_EvpSha384()) + mdName = JSTRING("SHA-384"); + else if (type == CryptoNative_EvpSha512()) + mdName = JSTRING("SHA-512"); + else if (type == CryptoNative_EvpMd5()) + mdName = JSTRING("MD5"); + else + return NULL; + + jobject mdObj = (*env)->CallStaticObjectMethod(env, g_mdClass, g_mdGetInstanceMethod, mdName); + (*env)->DeleteLocalRef(env, mdName); + + return CheckJNIExceptions(env) ? FAIL : mdObj; +} + +int32_t CryptoNative_EvpDigestOneShot(intptr_t type, void* source, int32_t sourceSize, uint8_t* md, uint32_t* mdSize) +{ + if (!type || !md || !mdSize || sourceSize < 0) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + + jobject mdObj = GetMessageDigestInstance(env, type); + if (!mdObj) + return FAIL; + + jbyteArray bytes = (*env)->NewByteArray(env, sourceSize); + (*env)->SetByteArrayRegion(env, bytes, 0, sourceSize, (jbyte*) source); + jbyteArray hashedBytes = (jbyteArray)(*env)->CallObjectMethod(env, mdObj, g_mdDigestMethod, bytes); + assert(hashedBytes && "MessageDigest.digest(...) was not expected to return null"); + + jsize hashedBytesLen = (*env)->GetArrayLength(env, hashedBytes); + (*env)->GetByteArrayRegion(env, hashedBytes, 0, hashedBytesLen, (jbyte*) md); + *mdSize = (uint32_t)hashedBytesLen; + + (*env)->DeleteLocalRef(env, bytes); + (*env)->DeleteLocalRef(env, hashedBytes); + (*env)->DeleteLocalRef(env, mdObj); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +jobject CryptoNative_EvpMdCtxCreate(intptr_t type) +{ + JNIEnv* env = GetJNIEnv(); + return (void*)ToGRef(env, GetMessageDigestInstance(env, type)); +} + +int32_t CryptoNative_EvpDigestReset(jobject ctx, intptr_t type) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + (*env)->CallVoidMethod(env, ctx, g_mdResetMethod); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +int32_t CryptoNative_EvpDigestUpdate(jobject ctx, void* d, int32_t cnt) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + + jbyteArray bytes = (*env)->NewByteArray(env, cnt); + (*env)->SetByteArrayRegion(env, bytes, 0, cnt, (jbyte*) d); + (*env)->CallVoidMethod(env, ctx, g_mdUpdateMethod, bytes); + (*env)->DeleteLocalRef(env, bytes); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +int32_t CryptoNative_EvpDigestFinalEx(jobject ctx, uint8_t* md, uint32_t* s) +{ + return CryptoNative_EvpDigestCurrent(ctx, md, s); +} + +int32_t CryptoNative_EvpDigestCurrent(jobject ctx, uint8_t* md, uint32_t* s) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + + jbyteArray bytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx, g_mdDigestCurrentMethodId); + assert(bytes && "digest() was not expected to return null"); + jsize bytesLen = (*env)->GetArrayLength(env, bytes); + *s = (uint32_t)bytesLen; + (*env)->GetByteArrayRegion(env, bytes, 0, bytesLen, (jbyte*) md); + (*env)->DeleteLocalRef(env, bytes); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +void CryptoNative_EvpMdCtxDestroy(jobject ctx) +{ + ReleaseGRef(GetJNIEnv(), ctx); +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp.h new file mode 100644 index 0000000000000..bf7ac3fb27795 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp.h @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "pal_jni.h" + +#define EVP_MAX_MD_SIZE 64 + +PALEXPORT int32_t CryptoNative_EvpMdSize(intptr_t md); +PALEXPORT int32_t CryptoNative_GetMaxMdSize(void); +PALEXPORT intptr_t CryptoNative_EvpMd5(void); +PALEXPORT intptr_t CryptoNative_EvpSha1(void); +PALEXPORT intptr_t CryptoNative_EvpSha256(void); +PALEXPORT intptr_t CryptoNative_EvpSha384(void); +PALEXPORT intptr_t CryptoNative_EvpSha512(void); +PALEXPORT int32_t CryptoNative_EvpDigestOneShot(intptr_t type, void* source, int32_t sourceSize, uint8_t* md, uint32_t* mdSize); +PALEXPORT jobject CryptoNative_EvpMdCtxCreate(intptr_t type); +PALEXPORT int32_t CryptoNative_EvpDigestReset(jobject ctx, intptr_t type); +PALEXPORT int32_t CryptoNative_EvpDigestUpdate(jobject ctx, void* d, int32_t cnt); +PALEXPORT int32_t CryptoNative_EvpDigestFinalEx(jobject ctx, uint8_t* md, uint32_t* s); +PALEXPORT int32_t CryptoNative_EvpDigestCurrent(jobject ctx, uint8_t* md, uint32_t* s); +PALEXPORT void CryptoNative_EvpMdCtxDestroy(jobject ctx); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp_cipher.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp_cipher.c new file mode 100644 index 0000000000000..00fc1c08d6ae6 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp_cipher.c @@ -0,0 +1,167 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_evp_cipher.h" + +// just some unique IDs +intptr_t CryptoNative_EvpAes128Ecb() { return 1001; } +intptr_t CryptoNative_EvpAes128Cbc() { return 1002; } +intptr_t CryptoNative_EvpAes128Cfb8() { return 1003; } +intptr_t CryptoNative_EvpAes128Cfb128() { return 1004; } +intptr_t CryptoNative_EvpAes128Gcm() { return 1005; } +intptr_t CryptoNative_EvpAes128Ccm() { return 1006; } +intptr_t CryptoNative_EvpAes192Ecb() { return 1007; } +intptr_t CryptoNative_EvpAes192Cbc() { return 1008; } +intptr_t CryptoNative_EvpAes192Cfb8() { return 1009; } +intptr_t CryptoNative_EvpAes192Cfb128() { return 1010; } +intptr_t CryptoNative_EvpAes192Gcm() { return 1011; } +intptr_t CryptoNative_EvpAes192Ccm() { return 1012; } +intptr_t CryptoNative_EvpAes256Ecb() { return 1013; } +intptr_t CryptoNative_EvpAes256Cbc() { return 1014; } +intptr_t CryptoNative_EvpAes256Cfb8() { return 1015; } +intptr_t CryptoNative_EvpAes256Cfb128() { return 1016; } +intptr_t CryptoNative_EvpAes256Gcm() { return 1017; } +intptr_t CryptoNative_EvpAes256Ccm() { return 1018; } +intptr_t CryptoNative_EvpDes3Ecb() { return 1019; } +intptr_t CryptoNative_EvpDes3Cbc() { return 1020; } +intptr_t CryptoNative_EvpDes3Cfb8() { return 1021; } +intptr_t CryptoNative_EvpDes3Cfb64() { return 1022; } +intptr_t CryptoNative_EvpDesEcb() { return 1023; } +intptr_t CryptoNative_EvpDesCfb8() { return 1024; } +intptr_t CryptoNative_EvpDesCbc() { return 1025; } +intptr_t CryptoNative_EvpRC2Ecb() { return 1026; } +intptr_t CryptoNative_EvpRC2Cbc() { return 1027; } + +jobject CryptoNative_EvpCipherCreate2(intptr_t type, uint8_t* key, int32_t keyLength, int32_t effectiveKeyLength, uint8_t* iv, int32_t enc) +{ + if (effectiveKeyLength != 0) + { + LOG_ERROR("Non-zero effectiveKeyLength is not supported"); + return FAIL; + } + + // input: 0 for Decrypt, 1 for Encrypt + // Cipher: 2 for Decrypt, 1 for Encrypt + assert(enc == 0 || enc == 1); + int encMode = enc == 0 ? 2 : 1; + + JNIEnv* env = GetJNIEnv(); + // Cipher cipher = Cipher.getInstance("AES"); + // int ivSize = cipher.getBlockSize(); + // SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES"); + // IvParameterSpec ivSpec = new IvParameterSpec(IV); + // cipher.init(encMode, keySpec, ivSpec); + + jobject algName = NULL; + + if ((type == CryptoNative_EvpAes128Cbc()) || + (type == CryptoNative_EvpAes192Cbc()) || + (type == CryptoNative_EvpAes256Cbc())) + { + algName = JSTRING("AES/CBC/NoPadding"); + } + else if ( + (type == CryptoNative_EvpAes128Ecb()) || + (type == CryptoNative_EvpAes192Ecb()) || + (type == CryptoNative_EvpAes256Ecb())) + { + algName = JSTRING("AES/ECB/NoPadding"); + } + else if ( + (type == CryptoNative_EvpAes128Cfb8()) || + (type == CryptoNative_EvpAes192Cfb8()) || + (type == CryptoNative_EvpAes256Cfb8())) + { + algName = JSTRING("AES/CFB/NoPadding"); + } + else + { + LOG_ERROR("unexpected type: %d", (int)type); + return FAIL; + } + + jobject cipherObj = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_cipherClass, g_cipherGetInstanceMethod, algName)); + + int blockSize = (*env)->CallIntMethod(env, cipherObj, g_getBlockSizeMethod); + jbyteArray keyBytes = (*env)->NewByteArray(env, keyLength / 8); // bits to bytes, e.g. 256 -> 32 + (*env)->SetByteArrayRegion(env, keyBytes, 0, keyLength / 8, (jbyte*)key); + jbyteArray ivBytes = (*env)->NewByteArray(env, blockSize); + (*env)->SetByteArrayRegion(env, ivBytes, 0, blockSize, (jbyte*)iv); + + jobject sksObj = (*env)->NewObject(env, g_sksClass, g_sksCtor, keyBytes, algName); + jobject ivPsObj = (*env)->NewObject(env, g_ivPsClass, g_ivPsCtor, ivBytes); + (*env)->CallVoidMethod(env, cipherObj, g_cipherInitMethod, encMode, sksObj, ivPsObj); + + (*env)->DeleteLocalRef(env, algName); + (*env)->DeleteLocalRef(env, sksObj); + (*env)->DeleteLocalRef(env, ivPsObj); + (*env)->DeleteLocalRef(env, keyBytes); + (*env)->DeleteLocalRef(env, ivBytes); + + return CheckJNIExceptions(env) ? FAIL : cipherObj; +} + +int32_t CryptoNative_EvpCipherUpdate(jobject ctx, uint8_t* outm, int32_t* outl, uint8_t* in, int32_t inl) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + jbyteArray inDataBytes = (*env)->NewByteArray(env, inl); + (*env)->SetByteArrayRegion(env, inDataBytes, 0, inl, (jbyte*)in); + jbyteArray outDataBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx, g_cipherUpdateMethod, inDataBytes); + if (outDataBytes) { + jsize outDataBytesLen = (*env)->GetArrayLength(env, outDataBytes); + *outl = (int32_t)outDataBytesLen; + (*env)->GetByteArrayRegion(env, outDataBytes, 0, outDataBytesLen, (jbyte*) outm); + (*env)->DeleteLocalRef(env, outDataBytes); + } else { + *outl = 0; + } + + (*env)->DeleteLocalRef(env, inDataBytes); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +int32_t CryptoNative_EvpCipherFinalEx(jobject ctx, uint8_t* outm, int32_t* outl) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + + int blockSize = (*env)->CallIntMethod(env, ctx, g_getBlockSizeMethod); + jbyteArray outBytes = (*env)->NewByteArray(env, blockSize); + int written = (*env)->CallIntMethod(env, ctx, g_cipherDoFinalMethod, outBytes, 0 /*offset*/); + if (written > 0) + (*env)->GetByteArrayRegion(env, outBytes, 0, blockSize, (jbyte*) outm); + *outl = written; + (*env)->DeleteLocalRef(env, outBytes); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +int32_t CryptoNative_EvpCipherCtxSetPadding(jobject ctx, int32_t padding) +{ + if (padding == 0) + { + return SUCCESS; + } + else + { + LOG_ERROR("Non-zero padding (%d) is not supported", (int)padding); + return FAIL; + } +} + +int32_t CryptoNative_EvpCipherReset(jobject ctx) +{ + // there is no "reset()" API for an existing Cipher object + return SUCCESS; +} + +void CryptoNative_EvpCipherDestroy(jobject ctx) +{ + ReleaseGRef(GetJNIEnv(), ctx); +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp_cipher.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp_cipher.h new file mode 100644 index 0000000000000..e0e11502c798f --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp_cipher.h @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "pal_jni.h" +#include "pal_evp.h" + +PALEXPORT jobject CryptoNative_EvpCipherCreate2(intptr_t type, uint8_t* key, int32_t keyLength, int32_t effectiveKeyLength, uint8_t* iv, int32_t enc); +PALEXPORT jobject CryptoNative_EvpCipherCreatePartial(intptr_t type); +PALEXPORT int32_t CryptoNative_EvpCipherSetKeyAndIV(jobject ctx, uint8_t* key, uint8_t* iv, int32_t enc); +PALEXPORT int32_t CryptoNative_EvpCipherSetGcmNonceLength(jobject ctx, int32_t ivLength); +PALEXPORT int32_t CryptoNative_EvpCipherSetCcmNonceLength(jobject ctx, int32_t ivLength); +PALEXPORT void CryptoNative_EvpCipherDestroy(jobject ctx); +PALEXPORT int32_t CryptoNative_EvpCipherReset(jobject ctx); +PALEXPORT int32_t CryptoNative_EvpCipherCtxSetPadding(jobject ctx, int32_t padding); +PALEXPORT int32_t CryptoNative_EvpCipherUpdate(jobject ctx, uint8_t* out, int32_t* outl, uint8_t* in, int32_t inl); +PALEXPORT int32_t CryptoNative_EvpCipherFinalEx(jobject ctx, uint8_t* outm, int32_t* outl); +PALEXPORT int32_t CryptoNative_EvpCipherGetGcmTag(jobject ctx, uint8_t* tag, int32_t tagLength); +PALEXPORT int32_t CryptoNative_EvpCipherSetGcmTag(jobject ctx, uint8_t* tag, int32_t tagLength); +PALEXPORT int32_t CryptoNative_EvpCipherGetCcmTag(jobject ctx, uint8_t* tag, int32_t tagLength); +PALEXPORT int32_t CryptoNative_EvpCipherSetCcmTag(jobject ctx, uint8_t* tag, int32_t tagLength); +PALEXPORT intptr_t CryptoNative_EvpAes128Ecb(void); +PALEXPORT intptr_t CryptoNative_EvpAes128Cbc(void); +PALEXPORT intptr_t CryptoNative_EvpAes128Cfb8(void); +PALEXPORT intptr_t CryptoNative_EvpAes128Cfb128(void); +PALEXPORT intptr_t CryptoNative_EvpAes128Gcm(void); +PALEXPORT intptr_t CryptoNative_EvpAes128Ccm(void); +PALEXPORT intptr_t CryptoNative_EvpAes192Ecb(void); +PALEXPORT intptr_t CryptoNative_EvpAes192Cbc(void); +PALEXPORT intptr_t CryptoNative_EvpAes192Cfb8(void); +PALEXPORT intptr_t CryptoNative_EvpAes192Cfb128(void); +PALEXPORT intptr_t CryptoNative_EvpAes192Gcm(void); +PALEXPORT intptr_t CryptoNative_EvpAes192Ccm(void); +PALEXPORT intptr_t CryptoNative_EvpAes256Ecb(void); +PALEXPORT intptr_t CryptoNative_EvpAes256Cbc(void); +PALEXPORT intptr_t CryptoNative_EvpAes256Cfb8(void); +PALEXPORT intptr_t CryptoNative_EvpAes256Cfb128(void); +PALEXPORT intptr_t CryptoNative_EvpAes256Gcm(void); +PALEXPORT intptr_t CryptoNative_EvpAes256Ccm(void); +PALEXPORT intptr_t CryptoNative_EvpDes3Ecb(void); +PALEXPORT intptr_t CryptoNative_EvpDes3Cbc(void); +PALEXPORT intptr_t CryptoNative_EvpDes3Cfb8(void); +PALEXPORT intptr_t CryptoNative_EvpDes3Cfb64(void); +PALEXPORT intptr_t CryptoNative_EvpDesEcb(void); +PALEXPORT intptr_t CryptoNative_EvpDesCfb8(void); +PALEXPORT intptr_t CryptoNative_EvpDesCbc(void); +PALEXPORT intptr_t CryptoNative_EvpRC2Ecb(void); +PALEXPORT intptr_t CryptoNative_EvpRC2Cbc(void); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_hmac.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_hmac.c new file mode 100644 index 0000000000000..390250e951081 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_hmac.c @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_evp.h" +#include "pal_hmac.h" + +jobject CryptoNative_HmacCreate(uint8_t* key, int32_t keyLen, intptr_t type) +{ + assert(key || (keyLen == 0)); + assert(keyLen >= 0); + + // Mac mac = Mac.getInstance(algName); + // SecretKeySpec key = new SecretKeySpec(key, algName); + // mac.init(key); + + JNIEnv* env = GetJNIEnv(); + + jstring macName = NULL; + if (type == CryptoNative_EvpSha1()) + macName = JSTRING("HmacSHA1"); + else if (type == CryptoNative_EvpSha256()) + macName = JSTRING("HmacSHA256"); + else if (type == CryptoNative_EvpSha384()) + macName = JSTRING("HmacSHA384"); + else if (type == CryptoNative_EvpSha512()) + macName = JSTRING("HmacSHA512"); + else if (type == CryptoNative_EvpMd5()) + macName = JSTRING("HmacMD5"); + else + return FAIL; + + jbyteArray keyBytes = (*env)->NewByteArray(env, keyLen); + (*env)->SetByteArrayRegion(env, keyBytes, 0, keyLen, (jbyte*)key); + jobject sksObj = (*env)->NewObject(env, g_sksClass, g_sksCtor, keyBytes, macName); + assert(sksObj && "Unable to create an instance of SecretKeySpec"); + jobject macObj = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_macClass, g_macGetInstanceMethod, macName)); + (*env)->CallVoidMethod(env, macObj, g_macInitMethod, sksObj); + (*env)->DeleteLocalRef(env, keyBytes); + (*env)->DeleteLocalRef(env, sksObj); + (*env)->DeleteLocalRef(env, macName); + + return CheckJNIExceptions(env) ? FAIL : macObj; +} + +int32_t CryptoNative_HmacReset(jobject ctx) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + (*env)->CallVoidMethod(env, ctx, g_macResetMethod); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +int32_t CryptoNative_HmacUpdate(jobject ctx, uint8_t* data, int32_t len) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + jbyteArray dataBytes = (*env)->NewByteArray(env, len); + (*env)->SetByteArrayRegion(env, dataBytes, 0, len, (jbyte*)data); + (*env)->CallVoidMethod(env, ctx, g_macUpdateMethod, dataBytes); + (*env)->DeleteLocalRef(env, dataBytes); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +int32_t CryptoNative_HmacFinal(jobject ctx, uint8_t* data, int32_t* len) +{ + return CryptoNative_HmacCurrent(ctx, data, len); +} + +int32_t CryptoNative_HmacCurrent(jobject ctx, uint8_t* data, int32_t* len) +{ + if (!ctx) + return FAIL; + + JNIEnv* env = GetJNIEnv(); + jbyteArray dataBytes = (jbyteArray)(*env)->CallObjectMethod(env, ctx, g_macDoFinalMethod); + jsize dataBytesLen = (*env)->GetArrayLength(env, dataBytes); + *len = (int32_t)dataBytesLen; + (*env)->GetByteArrayRegion(env, dataBytes, 0, dataBytesLen, (jbyte*) data); + (*env)->DeleteLocalRef(env, dataBytes); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} + +void CryptoNative_HmacDestroy(jobject ctx) +{ + ReleaseGRef(GetJNIEnv(), ctx); +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_hmac.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_hmac.h new file mode 100644 index 0000000000000..e44aa5d2570f2 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_hmac.h @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "pal_jni.h" + +PALEXPORT jobject CryptoNative_HmacCreate(uint8_t* key, int32_t keyLen, intptr_t md); +PALEXPORT int32_t CryptoNative_HmacReset(jobject ctx); +PALEXPORT int32_t CryptoNative_HmacUpdate(jobject ctx, uint8_t* data, int32_t len); +PALEXPORT int32_t CryptoNative_HmacFinal(jobject ctx, uint8_t* md, int32_t* len); +PALEXPORT int32_t CryptoNative_HmacCurrent(jobject ctx, uint8_t* md, int32_t* len); +PALEXPORT void CryptoNative_HmacDestroy(jobject ctx); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.c new file mode 100644 index 0000000000000..9a56e7581c0c7 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.c @@ -0,0 +1,155 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_jni.h" + +JavaVM* gJvm; + +// java/security/SecureRandom +jclass g_randClass; +jmethodID g_randCtor; +jmethodID g_randNextBytesMethod; + +// java/security/MessageDigest +jclass g_mdClass; +jmethodID g_mdGetInstanceMethod; +jmethodID g_mdDigestMethod; +jmethodID g_mdDigestCurrentMethodId; +jmethodID g_mdResetMethod; +jmethodID g_mdUpdateMethod; + +// javax/crypto/Mac +jclass g_macClass; +jmethodID g_macGetInstanceMethod; +jmethodID g_macDoFinalMethod; +jmethodID g_macUpdateMethod; +jmethodID g_macInitMethod; +jmethodID g_macResetMethod; + +// javax/crypto/spec/SecretKeySpec +jclass g_sksClass; +jmethodID g_sksCtor; + +// javax/crypto/Cipher +jclass g_cipherClass; +jmethodID g_cipherGetInstanceMethod; +jmethodID g_cipherDoFinalMethod; +jmethodID g_cipherUpdateMethod; +jmethodID g_cipherInitMethod; +jmethodID g_getBlockSizeMethod; + +// javax/crypto/spec/IvParameterSpec +jclass g_ivPsClass; +jmethodID g_ivPsCtor; + +// java/math/BigInteger +jclass g_bigNumClass; +jmethodID g_bigNumCtor; +jmethodID g_toByteArrayMethod; + +jobject ToGRef(JNIEnv *env, jobject lref) +{ + if (!lref) + return NULL; + jobject gref = (*env)->NewGlobalRef(env, lref); + (*env)->DeleteLocalRef(env, lref); + return gref; +} + +void ReleaseGRef(JNIEnv *env, jobject gref) +{ + if (gref) + (*env)->DeleteGlobalRef(env, gref); +} + +jclass GetClassGRef(JNIEnv *env, const char* name) +{ + LOG_DEBUG("Finding %s class", name); + jclass klass = ToGRef(env, (*env)->FindClass (env, name)); + if (!klass) { + LOG_ERROR("class %s was not found", name); + assert(klass); + } + return klass; +} + +bool CheckJNIExceptions(JNIEnv* env) +{ + if ((*env)->ExceptionCheck(env)) + { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + return true; + } + return false; +} + +jmethodID GetMethod(JNIEnv *env, bool isStatic, jclass klass, const char* name, const char* sig) +{ + LOG_DEBUG("Finding %s method", name); + jmethodID mid = isStatic ? (*env)->GetStaticMethodID(env, klass, name, sig) : (*env)->GetMethodID(env, klass, name, sig); + if (!mid) { + LOG_ERROR("method %s %s was not found", name, sig); + assert(mid); + } + return mid; +} + +JNIEnv* GetJNIEnv() +{ + JNIEnv *env; + (*gJvm)->GetEnv(gJvm, (void**)&env, JNI_VERSION_1_6); + if (env) + return env; + jint ret = (*gJvm)->AttachCurrentThreadAsDaemon(gJvm, &env, NULL); + assert(ret == JNI_OK && "Unable to attach thread to JVM"); + return env; +} + +PALEXPORT JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved) +{ + (void)reserved; + LOG_INFO("JNI_OnLoad in pal_jni.c"); + gJvm = vm; + + JNIEnv* env = GetJNIEnv(); + + // cache some classes and methods while we're in the thread-safe JNI_OnLoad + g_randClass = GetClassGRef(env, "java/security/SecureRandom"); + g_randCtor = GetMethod(env, false, g_randClass, "", "()V"); + g_randNextBytesMethod = GetMethod(env, false, g_randClass, "nextBytes", "([B)V"); + + g_mdClass = GetClassGRef(env, "java/security/MessageDigest"); + g_mdGetInstanceMethod = GetMethod(env, true, g_mdClass, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;"); + g_mdResetMethod = GetMethod(env, false, g_mdClass, "reset", "()V"); + g_mdDigestMethod = GetMethod(env, false, g_mdClass, "digest", "([B)[B"); + g_mdDigestCurrentMethodId = GetMethod(env, false, g_mdClass, "digest", "()[B"); + g_mdUpdateMethod = GetMethod(env, false, g_mdClass, "update", "([B)V"); + + g_macClass = GetClassGRef(env, "javax/crypto/Mac"); + g_macGetInstanceMethod = GetMethod(env, true, g_macClass, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Mac;"); + g_macDoFinalMethod = GetMethod(env, false, g_macClass, "doFinal", "()[B"); + g_macUpdateMethod = GetMethod(env, false, g_macClass, "update", "([B)V"); + g_macInitMethod = GetMethod(env, false, g_macClass, "init", "(Ljava/security/Key;)V"); + g_macResetMethod = GetMethod(env, false, g_macClass, "reset", "()V"); + + g_sksClass = GetClassGRef(env, "javax/crypto/spec/SecretKeySpec"); + g_sksCtor = GetMethod(env, false, g_sksClass, "", "([BLjava/lang/String;)V"); + + g_cipherClass = GetClassGRef(env, "javax/crypto/Cipher"); + g_cipherGetInstanceMethod = GetMethod(env, true, g_cipherClass, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Cipher;"); + g_getBlockSizeMethod = GetMethod(env, false, g_cipherClass, "getBlockSize", "()I"); + g_cipherDoFinalMethod = GetMethod(env, false, g_cipherClass, "doFinal", "([BI)I"); + g_cipherUpdateMethod = GetMethod(env, false, g_cipherClass, "update", "([B)[B"); + g_cipherInitMethod = GetMethod(env, false, g_cipherClass, "init", "(ILjava/security/Key;Ljava/security/spec/AlgorithmParameterSpec;)V"); + + g_ivPsClass = GetClassGRef(env, "javax/crypto/spec/IvParameterSpec"); + g_ivPsCtor = GetMethod(env, false, g_ivPsClass, "", "([B)V"); + + g_bigNumClass = GetClassGRef(env, "java/math/BigInteger"); + g_bigNumCtor = GetMethod(env, false, g_bigNumClass, "", "([B)V"); + g_toByteArrayMethod = GetMethod(env, false, g_bigNumClass, "toByteArray", "()[B"); + + return JNI_VERSION_1_6; +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.h new file mode 100644 index 0000000000000..9d63c89621241 --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.h @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include +#include +#include +#include "pal_safecrt.h" + +#define FAIL 0 +#define SUCCESS 1 + +extern JavaVM* gJvm; + +// java/security/SecureRandom +extern jclass g_randClass; +extern jmethodID g_randCtor; +extern jmethodID g_randNextBytesMethod; + +// java/security/MessageDigest +extern jclass g_mdClass; +extern jmethodID g_mdGetInstanceMethod; +extern jmethodID g_mdDigestMethod; +extern jmethodID g_mdDigestCurrentMethodId; +extern jmethodID g_mdResetMethod; +extern jmethodID g_mdUpdateMethod; + +// javax/crypto/Mac +extern jclass g_macClass; +extern jmethodID g_macGetInstanceMethod; +extern jmethodID g_macDoFinalMethod; +extern jmethodID g_macUpdateMethod; +extern jmethodID g_macInitMethod; +extern jmethodID g_macResetMethod; + +// javax/crypto/spec/SecretKeySpec +extern jclass g_sksClass; +extern jmethodID g_sksCtor; + +// javax/crypto/Cipher +extern jclass g_cipherClass; +extern jmethodID g_cipherGetInstanceMethod; +extern jmethodID g_cipherDoFinalMethod; +extern jmethodID g_cipherUpdateMethod; +extern jmethodID g_cipherInitMethod; +extern jmethodID g_getBlockSizeMethod; + +// javax/crypto/spec/IvParameterSpec +extern jclass g_ivPsClass; +extern jmethodID g_ivPsCtor; + +// java/math/BigInteger +extern jclass g_bigNumClass; +extern jmethodID g_bigNumCtor; +extern jmethodID g_toByteArrayMethod; + +// JNI helpers +#define LOG_DEBUG(fmt, ...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "DOTNET", "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)) +#define LOG_INFO(fmt, ...) ((void)__android_log_print(ANDROID_LOG_INFO, "DOTNET", "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)) +#define LOG_ERROR(fmt, ...) ((void)__android_log_print(ANDROID_LOG_ERROR, "DOTNET", "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)) +#define JSTRING(str) ((jstring)(*env)->NewStringUTF(env, str)) + +jobject ToGRef(JNIEnv *env, jobject lref); +void ReleaseGRef(JNIEnv *env, jobject gref); +jclass GetClassGRef(JNIEnv *env, const char* name); +bool CheckJNIExceptions(JNIEnv* env); +jmethodID GetMethod(JNIEnv *env, bool isStatic, jclass klass, const char* name, const char* sig); +JNIEnv* GetJNIEnv(void); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_misc.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_misc.c new file mode 100644 index 0000000000000..8bf1f9c75da7f --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_misc.c @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_misc.h" + +int32_t CryptoNative_EnsureOpenSslInitialized() +{ + return 0; +} + +int32_t CryptoNative_GetRandomBytes(uint8_t* buff, int32_t len) +{ + LOG_INFO("CryptoNative_GetRandomBytes"); + assert(g_randClass); + assert(g_randCtor); + JNIEnv* env = GetJNIEnv(); + jobject randObj = (*env)->NewObject(env, g_randClass, g_randCtor); + assert(randObj && "Unable to create an instance of java/security/SecureRandom"); + + jbyteArray buffArray = (*env)->NewByteArray(env, len); + (*env)->SetByteArrayRegion(env, buffArray, 0, len, (jbyte*)buff); + (*env)->CallVoidMethod(env, randObj, g_randNextBytesMethod, buffArray); + (*env)->GetByteArrayRegion(env, buffArray, 0, len, (jbyte*)buff); + + (*env)->DeleteLocalRef(env, buffArray); + (*env)->DeleteLocalRef(env, randObj); + + return CheckJNIExceptions(env) ? FAIL : SUCCESS; +} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_misc.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_misc.h new file mode 100644 index 0000000000000..d82c7c618bced --- /dev/null +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_misc.h @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +#include "pal_jni.h" + +PALEXPORT int32_t CryptoNative_EnsureOpenSslInitialized(void); +PALEXPORT int32_t CryptoNative_GetRandomBytes(uint8_t* buf, int32_t num); diff --git a/src/mono/netcore/sample/Android/AndroidSampleApp.csproj b/src/mono/netcore/sample/Android/AndroidSampleApp.csproj index d585f49418143..bddd119171951 100644 --- a/src/mono/netcore/sample/Android/AndroidSampleApp.csproj +++ b/src/mono/netcore/sample/Android/AndroidSampleApp.csproj @@ -55,7 +55,7 @@ - +