预期目标的描述
我正在尝试使用JNI在Android/Kotlin中实现OpenSSL生成的公钥/私钥对,以便对存储到云服务器的信息实现用户加密。我已经编译了所有的OpenSSL源代码,并正确地生成了所有.so文件。
代码(C++(
使用OpenSSL的C++代码如下所示。CmakeLists.txt和NDK配置运行良好。
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_eu_joober_ui_entry_SplashFragment_generateRSAKeyPair(JNIEnv *env, jobject thiz) {
int ret = 0;
RSA *r = nullptr;
BIGNUM *bne = nullptr;
BIO *bp_public = nullptr, *bp_private = nullptr;
int bits = 2048;
unsigned long e = RSA_F4;
jstring public_key_text;
jstring private_key_text;
jobjectArray returnPair = env->NewObjectArray(2, env->FindClass("java/lang/String"),nullptr);
// 1. generate rsa key
bne = BN_new();
ret = BN_set_word(bne,e);
if(ret != 1){
goto free_all;
}
r = RSA_new();
ret = RSA_generate_key_ex(r, bits, bne, nullptr);
if(ret != 1){
goto free_all;
}
// 2. get public key
bp_public = BIO_new(BIO_s_mem());
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
BIO_get_mem_data(bp_public, &public_key_text);
if(ret != 1){
goto free_all;
}
// 3. get private key
bp_private = BIO_new(BIO_s_mem());
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, nullptr, nullptr, 0, nullptr, nullptr);
BIO_get_mem_data(bp_private, &private_key_text);
// Check public and private keys were generated correctly
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Public key is: n%s",public_key_text);
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Private key is: n%s",private_key_text);
// 4. free
free_all:
BIO_free_all(bp_public);
BIO_free_all(bp_private);
RSA_free(r);
BN_free(bne);
// 5. Return strings using jobjectArray
if (ret == 1) {
env->SetObjectArrayElement(returnPair, 0, public_key_text);
env->SetObjectArrayElement(returnPair, 1, private_key_text);
return returnPair;
}
else {
return nullptr;
}
}
错误
如果我检查Android Logcat,公钥和私钥似乎都正确生成(根据__android_log_print
输出(,但当调用env->SetObjectArrayElement(returnPair, 0, public_key_text);
时,应用程序崩溃并出现以下错误:
JNI DETECTED ERROR IN APPLICATION: use of invalid jobject
IDE(Android Studio(没有抱怨任何错误,日志表明密钥对生成正确,但我不知道为什么密钥没有正确存储在jobjectArray中。事实上,如果我只是简单地说:
env->SetObjectArrayElement(returnPair, 0, env->NewStringUTF("Hello"));
env->SetObjectArrayElement(returnPair, 1, env->NewStringUTF("World"));
代码运行得很好,我的Kotlin代码正确地获得了字符串("Hello">和"World">(,并且应用程序没有崩溃,这让我认为问题只是在C++方面。
问题
我做错了什么?我检查了其他SO问题,比如JNI将jstring转换为char*或JNI程序中的jstring返回,但进行了轻微的修改和组合,但运气不佳。
旁注:我使用C++实现OpenSSL,因为Android/Kotlin代码不提供使用KeyPairGenerator.getInstance()
和generatePair()
生成的私钥(只能从Keystore检索公钥(,我需要将其存储在不同的位置,以便即使卸载了应用程序也可以检索用户信息,因为对CCD_ 6的每个后续调用将导致不同的密钥对。如果你知道解决这个问题的不同方法,我非常欢迎你提供任何建议。
您从未从public_key_text
创建过java字符串
尝试
char * public_key_text;
...
BIO_get_mem_data(bp_public, &public_key_text);
...
env->SetObjectArrayElement(returnPair, 0, env->NewStringUTF(public_key_text));