pal_hmac.c
pal_bignum.c
pal_ssl.c
+ pal_rsa.c
+ pal_err.c
)
add_library(System.Security.Cryptography.Native.Android
(*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;
+ return CheckJNIExceptions(env) ? FAIL : ToGRef(env, bigNum);
}
int32_t CryptoNative_BigNumToBinary(jobject bignum, uint8_t* output)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_err.h"
+
+void CryptoNative_ErrClearError()
+{
+}
+
+uint64_t CryptoNative_ErrGetErrorAlloc(int32_t* isAllocFailure)
+{
+ return 0;
+}
+
+uint64_t CryptoNative_ErrPeekError()
+{
+ return 0;
+}
+
+uint64_t CryptoNative_ErrPeekLastError()
+{
+ return 0;
+}
+
+const char* CryptoNative_ErrReasonErrorString(uint64_t error)
+{
+ return "See logcat for more details.";
+}
+
+void CryptoNative_ErrErrorStringN(uint64_t e, char* buf, int32_t len)
+{
+ buf = "See logcat for more details.";
+}
--- /dev/null
+// 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_ErrClearError(void);
+PALEXPORT uint64_t CryptoNative_ErrGetErrorAlloc(int32_t* isAllocFailure);
+PALEXPORT uint64_t CryptoNative_ErrPeekError(void);
+PALEXPORT uint64_t CryptoNative_ErrPeekLastError(void);
+PALEXPORT const char* CryptoNative_ErrReasonErrorString(uint64_t error);
+PALEXPORT void CryptoNative_ErrErrorStringN(uint64_t e, char* buf, int32_t len);
jclass g_cipherClass;
jmethodID g_cipherGetInstanceMethod;
jmethodID g_cipherDoFinalMethod;
+jmethodID g_cipherDoFinal2Method;
jmethodID g_cipherUpdateMethod;
jmethodID g_cipherUpdateAADMethod;
jmethodID g_cipherInitMethod;
+jmethodID g_cipherInit2Method;
jmethodID g_getBlockSizeMethod;
// javax/crypto/spec/IvParameterSpec
jclass g_GCMParameterSpecClass;
jmethodID g_GCMParameterSpecCtor;
+// java/security/interfaces/RSAKey
+jclass g_RSAKeyClass;
+jmethodID g_RSAKeyGetModulus;
+
+// java/security/interfaces/RSAPublicKey
+jclass g_RSAPublicKeyClass;
+jmethodID g_RSAPublicKeyGetPubExpMethod;
+
+// java/security/KeyPair
+jclass g_keyPairClass;
+jmethodID g_keyPairGetPrivateMethod;
+jmethodID g_keyPairGetPublicMethod;
+
+// java/security/KeyPairGenerator
+jclass g_keyPairGenClass;
+jmethodID g_keyPairGenGetInstanceMethod;
+jmethodID g_keyPairGenInitializeMethod;
+jmethodID g_keyPairGenGenKeyPairMethod;
+
+// java/security/interfaces/RSAPrivateCrtKey
+jclass g_RSAPrivateCrtKeyClass;
+jmethodID g_RSAPrivateCrtKeyPubExpField;
+jmethodID g_RSAPrivateCrtKeyPrimePField;
+jmethodID g_RSAPrivateCrtKeyPrimeQField;
+jmethodID g_RSAPrivateCrtKeyPrimeExpPField;
+jmethodID g_RSAPrivateCrtKeyPrimeExpQField;
+jmethodID g_RSAPrivateCrtKeyCrtCoefField;
+jmethodID g_RSAPrivateCrtKeyModulusField;
+jmethodID g_RSAPrivateCrtKeyPrivExpField;
+
+// java/security/spec/RSAPrivateCrtKeySpec
+jclass g_RSAPrivateCrtKeySpecClass;
+jmethodID g_RSAPrivateCrtKeySpecCtor;
+
+// java/security/spec/RSAPublicKeySpec
+jclass g_RSAPublicCrtKeySpecClass;
+jmethodID g_RSAPublicCrtKeySpecCtor;
+
+// java/security/KeyFactory
+jclass g_KeyFactoryClass;
+jmethodID g_KeyFactoryGetInstanceMethod;
+jmethodID g_KeyFactoryGenPrivateMethod;
+jmethodID g_KeyFactoryGenPublicMethod;
+
+// java/security/spec/X509EncodedKeySpec
+jclass g_X509EncodedKeySpecClass;
+jmethodID g_X509EncodedKeySpecCtor;
+
+// com/android/org/conscrypt/NativeCrypto
+jclass g_NativeCryptoClass;
+
jobject ToGRef(JNIEnv *env, jobject lref)
{
if (!lref)
return gref;
}
+jobject AddGRef(JNIEnv *env, jobject gref)
+{
+ if (!gref)
+ return NULL;
+ return (*env)->NewGlobalRef(env, gref);
+}
+
void ReleaseGRef(JNIEnv *env, jobject gref)
{
if (gref)
return mid;
}
+jfieldID GetField(JNIEnv *env, bool isStatic, jclass klass, const char* name, const char* sig)
+{
+ LOG_DEBUG("Finding %s field", name);
+ jfieldID fid = isStatic ? (*env)->GetStaticFieldID(env, klass, name, sig) : (*env)->GetFieldID(env, klass, name, sig);
+ if (!fid) {
+ LOG_ERROR("field %s %s was not found", name, sig);
+ assert(fid);
+ }
+ return fid;
+}
+
JNIEnv* GetJNIEnv()
{
JNIEnv *env;
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", "()[B");
+ g_cipherDoFinal2Method = GetMethod(env, false, g_cipherClass, "doFinal", "([B)[B");
g_cipherUpdateMethod = GetMethod(env, false, g_cipherClass, "update", "([B)[B");
g_cipherUpdateAADMethod = GetMethod(env, false, g_cipherClass, "updateAAD", "([B)V");
g_cipherInitMethod = GetMethod(env, false, g_cipherClass, "init", "(ILjava/security/Key;Ljava/security/spec/AlgorithmParameterSpec;)V");
+ g_cipherInit2Method = GetMethod(env, false, g_cipherClass, "init", "(ILjava/security/Key;)V");
g_ivPsClass = GetClassGRef(env, "javax/crypto/spec/IvParameterSpec");
g_ivPsCtor = GetMethod(env, false, g_ivPsClass, "<init>", "([B)V");
g_sslCtxGetDefaultMethod = GetMethod(env, true, g_sslCtxClass, "getDefault", "()Ljavax/net/ssl/SSLContext;");
g_sslCtxGetDefaultSslParamsMethod = GetMethod(env, false, g_sslCtxClass, "getDefaultSSLParameters", "()Ljavax/net/ssl/SSLParameters;");
+ g_RSAKeyClass = GetClassGRef(env, "java/security/interfaces/RSAKey");
+ g_RSAKeyGetModulus = GetMethod(env, false, g_RSAKeyClass, "getModulus", "()Ljava/math/BigInteger;");
+
+ g_RSAPublicKeyClass = GetClassGRef(env, "java/security/interfaces/RSAPublicKey");
+ g_RSAPublicKeyGetPubExpMethod = GetMethod(env, false, g_RSAPublicKeyClass, "getPublicExponent", "()Ljava/math/BigInteger;");
+
+ g_keyPairClass = GetClassGRef(env, "java/security/KeyPair");
+ g_keyPairGetPrivateMethod = GetMethod(env, false, g_keyPairClass, "getPrivate", "()Ljava/security/PrivateKey;");
+ g_keyPairGetPublicMethod = GetMethod(env, false, g_keyPairClass, "getPublic", "()Ljava/security/PublicKey;");
+
+ g_keyPairGenClass = GetClassGRef(env, "java/security/KeyPairGenerator");
+ g_keyPairGenGetInstanceMethod = GetMethod(env, true, g_keyPairGenClass, "getInstance", "(Ljava/lang/String;)Ljava/security/KeyPairGenerator;");
+ g_keyPairGenInitializeMethod = GetMethod(env, false, g_keyPairGenClass, "initialize", "(I)V");
+ g_keyPairGenGenKeyPairMethod = GetMethod(env, false, g_keyPairGenClass, "genKeyPair", "()Ljava/security/KeyPair;");
+
+ g_RSAPrivateCrtKeyClass = GetClassGRef(env, "java/security/interfaces/RSAPrivateCrtKey");
+ g_RSAPrivateCrtKeyPubExpField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getPublicExponent", "()Ljava/math/BigInteger;");
+ g_RSAPrivateCrtKeyPrimePField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getPrimeP", "()Ljava/math/BigInteger;");
+ g_RSAPrivateCrtKeyPrimeQField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getPrimeQ", "()Ljava/math/BigInteger;");
+ g_RSAPrivateCrtKeyPrimeExpPField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getPrimeExponentP", "()Ljava/math/BigInteger;");
+ g_RSAPrivateCrtKeyPrimeExpQField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getPrimeExponentQ", "()Ljava/math/BigInteger;");
+ g_RSAPrivateCrtKeyCrtCoefField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getCrtCoefficient", "()Ljava/math/BigInteger;");
+ g_RSAPrivateCrtKeyModulusField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getModulus", "()Ljava/math/BigInteger;");
+ g_RSAPrivateCrtKeyPrivExpField = GetMethod(env, false, g_RSAPrivateCrtKeyClass, "getPrivateExponent", "()Ljava/math/BigInteger;");
+
+ g_RSAPrivateCrtKeySpecClass = GetClassGRef(env, "java/security/spec/RSAPrivateCrtKeySpec");
+ g_RSAPrivateCrtKeySpecCtor = GetMethod(env, false, g_RSAPrivateCrtKeySpecClass, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;Ljava/math/BigInteger;Ljava/math/BigInteger;Ljava/math/BigInteger;Ljava/math/BigInteger;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+
+ g_RSAPublicCrtKeySpecClass = GetClassGRef(env, "java/security/spec/RSAPublicKeySpec");
+ g_RSAPublicCrtKeySpecCtor = GetMethod(env, false, g_RSAPublicCrtKeySpecClass, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+
+ g_KeyFactoryClass = GetClassGRef(env, "java/security/KeyFactory");
+ g_KeyFactoryGetInstanceMethod = GetMethod(env, true, g_KeyFactoryClass, "getInstance", "(Ljava/lang/String;)Ljava/security/KeyFactory;");
+ g_KeyFactoryGenPrivateMethod = GetMethod(env, false, g_KeyFactoryClass, "generatePrivate", "(Ljava/security/spec/KeySpec;)Ljava/security/PrivateKey;");
+ g_KeyFactoryGenPublicMethod = GetMethod(env, false, g_KeyFactoryClass, "generatePublic", "(Ljava/security/spec/KeySpec;)Ljava/security/PublicKey;");
+
+ g_X509EncodedKeySpecClass = GetClassGRef(env, "java/security/spec/X509EncodedKeySpec");
+ g_X509EncodedKeySpecCtor = GetMethod(env, false, g_X509EncodedKeySpecClass, "<init>", "([B)V");
+
+ g_NativeCryptoClass = GetClassGRef(env, "com/android/org/conscrypt/NativeCrypto");
+
return JNI_VERSION_1_6;
}
extern jclass g_cipherClass;
extern jmethodID g_cipherGetInstanceMethod;
extern jmethodID g_cipherDoFinalMethod;
+extern jmethodID g_cipherDoFinal2Method;
extern jmethodID g_cipherUpdateMethod;
extern jmethodID g_cipherUpdateAADMethod;
extern jmethodID g_cipherInitMethod;
+extern jmethodID g_cipherInit2Method;
extern jmethodID g_getBlockSizeMethod;
// javax/crypto/spec/IvParameterSpec
extern jclass g_GCMParameterSpecClass;
extern jmethodID g_GCMParameterSpecCtor;
+// java/security/interfaces/RSAKey
+extern jclass g_RSAKeyClass;
+extern jmethodID g_RSAKeyGetModulus;
+
+// java/security/interfaces/RSAPublicKey
+extern jclass g_RSAPublicKeyClass;
+extern jmethodID g_RSAPublicKeyGetPubExpMethod;
+
+// java/security/KeyPair
+extern jclass g_keyPairClass;
+extern jmethodID g_keyPairGetPrivateMethod;
+extern jmethodID g_keyPairGetPublicMethod;
+
+// java/security/KeyPairGenerator
+extern jclass g_keyPairGenClass;
+extern jmethodID g_keyPairGenGetInstanceMethod;
+extern jmethodID g_keyPairGenInitializeMethod;
+extern jmethodID g_keyPairGenGenKeyPairMethod;
+
+// com/android/org/conscrypt/RSAPrivateCrtKey
+extern jclass g_RSAPrivateCrtKeyClass;
+extern jmethodID g_RSAPrivateCrtKeyPubExpField;
+extern jmethodID g_RSAPrivateCrtKeyPrimePField;
+extern jmethodID g_RSAPrivateCrtKeyPrimeQField;
+extern jmethodID g_RSAPrivateCrtKeyPrimeExpPField;
+extern jmethodID g_RSAPrivateCrtKeyPrimeExpQField;
+extern jmethodID g_RSAPrivateCrtKeyCrtCoefField;
+extern jmethodID g_RSAPrivateCrtKeyModulusField;
+extern jmethodID g_RSAPrivateCrtKeyPrivExpField;
+
+// java/security/spec/RSAPrivateCrtKeySpec
+extern jclass g_RSAPrivateCrtKeySpecClass;
+extern jmethodID g_RSAPrivateCrtKeySpecCtor;
+
+// java/security/spec/RSAPublicKeySpec
+extern jclass g_RSAPublicCrtKeySpecClass;
+extern jmethodID g_RSAPublicCrtKeySpecCtor;
+
+// java/security/KeyFactory
+extern jclass g_KeyFactoryClass;
+extern jmethodID g_KeyFactoryGetInstanceMethod;
+extern jmethodID g_KeyFactoryGenPrivateMethod;
+extern jmethodID g_KeyFactoryGenPublicMethod;
+
+// java/security/spec/X509EncodedKeySpec
+extern jclass g_X509EncodedKeySpecClass;
+extern jmethodID g_X509EncodedKeySpecCtor;
+
+// com/android/org/conscrypt/NativeCrypto
+extern jclass g_NativeCryptoClass;
+
// 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__))
void SaveTo(uint8_t* src, uint8_t** dst, size_t len);
jobject ToGRef(JNIEnv *env, jobject lref);
+jobject AddGRef(JNIEnv *env, jobject gref);
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);
+jfieldID GetField(JNIEnv *env, bool isStatic, jclass klass, const char* name, const char* sig);
JNIEnv* GetJNIEnv(void);
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "pal_rsa.h"
+
+PALEXPORT RSA* CryptoNative_RsaCreate()
+{
+ RSA* rsa = malloc(sizeof(RSA));
+ rsa->privateKey = NULL;
+ rsa->publicKey = NULL;
+ rsa->pubExp = NULL;
+ rsa->keyWidth = 0;
+ rsa->refCount = 1;
+ return rsa;
+}
+
+PALEXPORT int32_t CryptoNative_RsaUpRef(RSA* rsa)
+{
+ if (!rsa)
+ return FAIL;
+ rsa->refCount++;
+ return SUCCESS;
+}
+
+PALEXPORT void CryptoNative_RsaDestroy(RSA* rsa)
+{
+ if (rsa)
+ {
+ rsa->refCount--;
+ if (rsa->refCount == 0)
+ {
+ JNIEnv* env = GetJNIEnv();
+ ReleaseGRef(env, rsa->privateKey);
+ ReleaseGRef(env, rsa->publicKey);
+ ReleaseGRef(env, rsa->pubExp);
+ free(rsa);
+ }
+ }
+}
+
+PALEXPORT int32_t CryptoNative_RsaPublicEncrypt(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding)
+{
+ if (!rsa)
+ return FAIL;
+
+ JNIEnv* env = GetJNIEnv();
+
+ jobject algName;
+ if (padding == Pkcs1)
+ algName = JSTRING("RSA/ECB/PKCS1Padding");
+ else if (padding == OaepSHA1)
+ algName = JSTRING("RSA/ECB/OAEPPadding");
+ else
+ algName = JSTRING("RSA/ECB/NoPadding");
+
+ jobject cipher = (*env)->CallStaticObjectMethod(env, g_cipherClass, g_cipherGetInstanceMethod, algName);
+ (*env)->CallVoidMethod(env, cipher, g_cipherInit2Method, CIPHER_ENCRYPT_MODE, rsa->publicKey);
+ jbyteArray fromBytes = (*env)->NewByteArray(env, flen);
+ (*env)->SetByteArrayRegion(env, fromBytes, 0, flen, (jbyte*)from);
+ jbyteArray encryptedBytes = (jbyteArray)(*env)->CallObjectMethod(env, cipher, g_cipherDoFinal2Method, fromBytes);
+ jsize encryptedBytesLen = (*env)->GetArrayLength(env, encryptedBytes);
+ (*env)->GetByteArrayRegion(env, encryptedBytes, 0, encryptedBytesLen, (jbyte*) to);
+
+ (*env)->DeleteLocalRef(env, cipher);
+ (*env)->DeleteLocalRef(env, fromBytes);
+ (*env)->DeleteLocalRef(env, encryptedBytes);
+ (*env)->DeleteLocalRef(env, algName);
+
+ return (int32_t)encryptedBytesLen;
+}
+
+PALEXPORT int32_t CryptoNative_RsaPrivateDecrypt(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding)
+{
+ if (!rsa)
+ return FAIL;
+
+ JNIEnv* env = GetJNIEnv();
+
+ jobject algName;
+ if (padding == Pkcs1)
+ algName = JSTRING("RSA/ECB/PKCS1Padding"); // TODO: is ECB needed here?
+ else if (padding == OaepSHA1)
+ algName = JSTRING("RSA/ECB/OAEPPadding");
+ else
+ algName = JSTRING("RSA/ECB/NoPadding");
+
+ jobject cipher = (*env)->CallStaticObjectMethod(env, g_cipherClass, g_cipherGetInstanceMethod, algName);
+ (*env)->CallVoidMethod(env, cipher, g_cipherInit2Method, CIPHER_DECRYPT_MODE, rsa->privateKey);
+ jbyteArray fromBytes = (*env)->NewByteArray(env, flen);
+ (*env)->SetByteArrayRegion(env, fromBytes, 0, flen, (jbyte*)from);
+ jbyteArray decryptedBytes = (jbyteArray)(*env)->CallObjectMethod(env, cipher, g_cipherDoFinal2Method, fromBytes);
+ jsize decryptedBytesLen = (*env)->GetArrayLength(env, decryptedBytes);
+ (*env)->GetByteArrayRegion(env, decryptedBytes, 0, decryptedBytesLen, (jbyte*) to);
+
+ (*env)->DeleteLocalRef(env, cipher);
+ (*env)->DeleteLocalRef(env, fromBytes);
+ (*env)->DeleteLocalRef(env, decryptedBytes);
+ (*env)->DeleteLocalRef(env, algName);
+
+ return (int32_t)decryptedBytesLen;
+}
+
+PALEXPORT int32_t CryptoNative_RsaSize(RSA* rsa)
+{
+ if (!rsa)
+ return FAIL;
+ return rsa->keyWidth / 8;
+}
+
+PALEXPORT RSA* CryptoNative_DecodeRsaPublicKey(uint8_t* buf, int32_t len)
+{
+ if (!buf || !len)
+ {
+ return NULL;
+ }
+
+ JNIEnv* env = GetJNIEnv();
+
+ // KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ // X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(bytes);
+ // PublicKey publicKey = keyFactory.generatePublic(x509keySpec);
+
+ jobject algName = JSTRING("RSA");
+ jobject keyFactory = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, algName);
+ jbyteArray bytes = (*env)->NewByteArray(env, len);
+ (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)buf);
+ jobject x509keySpec = (*env)->NewObject(env, g_X509EncodedKeySpecClass, g_X509EncodedKeySpecCtor, bytes);
+
+ RSA* rsa = CryptoNative_RsaCreate();
+ rsa->publicKey = ToGRef(env, (*env)->CallObjectMethod(env, keyFactory, g_KeyFactoryGenPublicMethod, x509keySpec));
+
+ (*env)->DeleteLocalRef(env, algName);
+ (*env)->DeleteLocalRef(env, keyFactory);
+ (*env)->DeleteLocalRef(env, bytes);
+ (*env)->DeleteLocalRef(env, x509keySpec);
+
+ return rsa;
+}
+
+PALEXPORT int32_t CryptoNative_RsaSignPrimitive(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa)
+{
+ // TODO:
+ return FAIL;
+}
+
+PALEXPORT int32_t CryptoNative_RsaVerificationPrimitive(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa)
+{
+ // TODO:
+ return FAIL;
+}
+
+PALEXPORT int32_t CryptoNative_RsaSign(int32_t type, uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa)
+{
+ // TODO:
+ return FAIL;
+}
+
+PALEXPORT int32_t CryptoNative_RsaVerify(int32_t type, uint8_t* m, int32_t mlen, uint8_t* sigbuf, int32_t siglen, RSA* rsa)
+{
+ // TODO:
+ return FAIL;
+}
+
+PALEXPORT int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, jobject pubExp)
+{
+ if (!rsa)
+ return FAIL;
+
+ // KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ // kpg.initialize(bits);
+ // KeyPair kp = kpg.genKeyPair();
+
+ JNIEnv* env = GetJNIEnv();
+ jobject rsaStr = JSTRING("RSA");
+ jobject kpgObj = (*env)->CallStaticObjectMethod(env, g_keyPairGenClass, g_keyPairGenGetInstanceMethod, rsaStr);
+ (*env)->CallVoidMethod(env, kpgObj, g_keyPairGenInitializeMethod, bits);
+ jobject keyPair = (*env)->CallObjectMethod(env, kpgObj, g_keyPairGenGenKeyPairMethod);
+
+ rsa->privateKey = ToGRef(env, (*env)->CallObjectMethod(env, keyPair, g_keyPairGetPrivateMethod));
+ rsa->publicKey = ToGRef(env, (*env)->CallObjectMethod(env, keyPair, g_keyPairGetPublicMethod));
+ rsa->keyWidth = bits;
+ // pubExp is already expected to be a gref at this point but we need to create another one.
+ rsa->pubExp = AddGRef(env, pubExp);
+
+ (*env)->DeleteLocalRef(env, rsaStr);
+ (*env)->DeleteLocalRef(env, kpgObj);
+ (*env)->DeleteLocalRef(env, keyPair);
+
+ return CheckJNIExceptions(env) ? FAIL : SUCCESS;
+}
+
+PALEXPORT int32_t CryptoNative_GetRsaParameters(RSA* rsa,
+ jobject* n, jobject* e, jobject* d, jobject* p, jobject* dmp1, jobject* q, jobject* dmq1, jobject* iqmp)
+{
+ if (!rsa || !n || !e || !d || !p || !dmp1 || !q || !dmq1 || !iqmp)
+ {
+ assert(false);
+
+ // since these parameters are 'out' parameters in managed code, ensure they are initialized
+ if (n)
+ *n = NULL;
+ if (e)
+ *e = NULL;
+ if (d)
+ *d = NULL;
+ if (p)
+ *p = NULL;
+ if (dmp1)
+ *dmp1 = NULL;
+ if (q)
+ *q = NULL;
+ if (dmq1)
+ *dmq1 = NULL;
+ if (iqmp)
+ *iqmp = NULL;
+
+ return FAIL;
+ }
+
+ JNIEnv* env = GetJNIEnv();
+ jobject privateKey = rsa->privateKey;
+ jobject publicKey = rsa->publicKey;
+
+ if (privateKey)
+ {
+ *e = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyPubExpField));
+ *n = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyModulusField));
+ *d = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyPrivExpField));
+ *p = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyPrimePField));
+ *q = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyPrimeQField));
+ *dmp1 = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyPrimeExpPField));
+ *dmq1 = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyPrimeExpQField));
+ *iqmp = ToGRef(env, (*env)->CallObjectMethod(env, privateKey, g_RSAPrivateCrtKeyCrtCoefField));
+ }
+ else
+ {
+ assert(publicKey);
+ *e = ToGRef(env, (*env)->CallObjectMethod(env, publicKey, g_RSAPublicKeyGetPubExpMethod));
+ *n = ToGRef(env, (*env)->CallObjectMethod(env, publicKey, g_RSAKeyGetModulus));
+ *d = NULL;
+ *p = NULL;
+ *q = NULL;
+ *dmp1 = NULL;
+ *dmq1 = NULL;
+ *iqmp = NULL;
+ }
+
+ return CheckJNIExceptions(env) ? FAIL : SUCCESS;
+}
+
+jobject BigNumFromBinary(JNIEnv* env, uint8_t* bytes, int32_t len)
+{
+ assert(len > 0);
+ 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 bigNum;
+}
+
+PALEXPORT int32_t CryptoNative_SetRsaParameters(RSA* rsa,
+ uint8_t* n, int32_t nLength, uint8_t* e, int32_t eLength, uint8_t* d, int32_t dLength,
+ uint8_t* p, int32_t pLength, uint8_t* dmp1, int32_t dmp1Length, uint8_t* q, int32_t qLength,
+ uint8_t* dmq1, int32_t dmq1Length, uint8_t* iqmp, int32_t iqmpLength)
+{
+ if (!rsa)
+ return FAIL;
+
+ JNIEnv* env = GetJNIEnv();
+
+ jobject nObj = BigNumFromBinary(env, n, nLength);
+ jobject eObj = BigNumFromBinary(env, e, eLength);
+
+ rsa->keyWidth = (nLength - 1) * 8; // Android SDK has an extra byte in Modulus(?)
+
+ jobject algName = JSTRING("RSA");
+ jobject keyFactory = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, algName);
+
+ if (dLength > 0)
+ {
+ // private key section
+ jobject dObj = BigNumFromBinary(env, d, dLength);
+ jobject pObj = BigNumFromBinary(env, p, pLength);
+ jobject qObj = BigNumFromBinary(env, q, qLength);
+ jobject dmp1Obj = BigNumFromBinary(env, dmp1, dmp1Length);
+ jobject dmq1Obj = BigNumFromBinary(env, dmq1, dmq1Length);
+ jobject iqmpObj = BigNumFromBinary(env, iqmp, iqmpLength);
+
+ jobject rsaPrivateKeySpec = (*env)->NewObject(env, g_RSAPrivateCrtKeySpecClass, g_RSAPrivateCrtKeySpecCtor,
+ nObj, eObj, dObj, pObj, qObj, dmp1Obj, dmq1Obj, iqmpObj);
+
+ ReleaseGRef(env, rsa->privateKey);
+ rsa->privateKey = ToGRef(env, (*env)->CallObjectMethod(env, keyFactory, g_KeyFactoryGenPrivateMethod, rsaPrivateKeySpec));
+
+ (*env)->DeleteLocalRef(env, dObj);
+ (*env)->DeleteLocalRef(env, pObj);
+ (*env)->DeleteLocalRef(env, qObj);
+ (*env)->DeleteLocalRef(env, dmp1Obj);
+ (*env)->DeleteLocalRef(env, dmq1Obj);
+ (*env)->DeleteLocalRef(env, iqmpObj);
+ (*env)->DeleteLocalRef(env, rsaPrivateKeySpec);
+ }
+
+ jobject rsaPubKeySpec = (*env)->NewObject(env, g_RSAPublicCrtKeySpecClass, g_RSAPublicCrtKeySpecCtor, nObj, eObj);
+
+ ReleaseGRef(env, rsa->publicKey);
+ rsa->publicKey = ToGRef(env, (*env)->CallObjectMethod(env, keyFactory, g_KeyFactoryGenPublicMethod, rsaPubKeySpec));
+
+ (*env)->DeleteLocalRef(env, algName);
+ (*env)->DeleteLocalRef(env, keyFactory);
+ (*env)->DeleteLocalRef(env, nObj);
+ (*env)->DeleteLocalRef(env, eObj);
+ (*env)->DeleteLocalRef(env, rsaPubKeySpec);
+
+ return CheckJNIExceptions(env) ? FAIL : SUCCESS;
+}
--- /dev/null
+// 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"
+
+typedef enum
+{
+ Pkcs1 = 0,
+ OaepSHA1 = 1,
+ NoPadding = 2,
+} RsaPadding;
+
+typedef struct RSA
+{
+ jobject pubExp;
+ jobject privateKey; // RSAPrivateCrtKey
+ jobject publicKey; // RSAPublicCrtKey
+ int32_t refCount;
+ int32_t keyWidth;
+} RSA;
+
+#define CIPHER_ENCRYPT_MODE 1
+#define CIPHER_DECRYPT_MODE 2
+
+jobject BigNumFromBinary(JNIEnv* env, uint8_t* bytes, int32_t len);
+
+PALEXPORT RSA* CryptoNative_RsaCreate(void);
+PALEXPORT int32_t CryptoNative_RsaUpRef(RSA* rsa);
+PALEXPORT void CryptoNative_RsaDestroy(RSA* rsa);
+PALEXPORT RSA* CryptoNative_DecodeRsaPublicKey(uint8_t* buf, int32_t len);
+PALEXPORT int32_t CryptoNative_RsaPublicEncrypt(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding);
+PALEXPORT int32_t CryptoNative_RsaPrivateDecrypt(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding);
+PALEXPORT int32_t CryptoNative_RsaSignPrimitive(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa);
+PALEXPORT int32_t CryptoNative_RsaVerificationPrimitive(int32_t flen, uint8_t* from, uint8_t* to, RSA* rsa);
+PALEXPORT int32_t CryptoNative_RsaSize(RSA* rsa);
+PALEXPORT int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, jobject pubExp);
+PALEXPORT int32_t CryptoNative_RsaSign(int32_t type, uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa);
+PALEXPORT int32_t CryptoNative_RsaVerify(int32_t type, uint8_t* m, int32_t mlen, uint8_t* sigbuf, int32_t siglen, RSA* rsa);
+PALEXPORT int32_t CryptoNative_GetRsaParameters(RSA* rsa,
+ jobject* n, jobject* e, jobject* d, jobject* p, jobject* dmp1, jobject* q, jobject* dmq1, jobject* iqmp);
+PALEXPORT int32_t CryptoNative_SetRsaParameters(RSA* rsa,
+ uint8_t* n, int32_t nLength, uint8_t* e, int32_t eLength, uint8_t* d, int32_t dLength,
+ uint8_t* p, int32_t pLength, uint8_t* dmp1, int32_t dmp1Length, uint8_t* q, int32_t qLength,
+ uint8_t* dmq1, int32_t dmq1Length, uint8_t* iqmp, int32_t iqmpLength);