应用程序中的 JNI 检测到错误:返回字符串数组时使用了无效的 jobject
JNI DETECTED ERROR IN APPLICATION: use of invalid jobject when returning Array of String
预期目标的描述
我正在尝试使用 JNI 在 Android/Kotlin 中实施 OpenSSL 生成的 public/private 密钥对,以便对存储到云服务器的信息实施用户加密。我编译了所有 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,public 和私钥似乎都已正确生成(根据 __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 converting jstring to char * or jstring return in JNI program,只是稍加修改和组合,但没有运气。
SIDE 注意:我在 C++ 中使用 OpenSSL 实现,因为 Android/Kotlin 代码不提供使用 [=15= 生成的私钥] 和 generatePair()
(只能从 Keystore 中检索到 public 密钥),我需要将其存储在不同的地方,以便即使应用程序被卸载也可以检索用户信息,因为每次后续调用到 generatePair()
将导致不同的密钥对。如果您知道解决此问题的不同方法,我非常欢迎您提供任何建议。
您从未从 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));
预期目标的描述
我正在尝试使用 JNI 在 Android/Kotlin 中实施 OpenSSL 生成的 public/private 密钥对,以便对存储到云服务器的信息实施用户加密。我编译了所有 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,public 和私钥似乎都已正确生成(根据 __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 converting jstring to char * or jstring return in JNI program,只是稍加修改和组合,但没有运气。
SIDE 注意:我在 C++ 中使用 OpenSSL 实现,因为 Android/Kotlin 代码不提供使用 [=15= 生成的私钥] 和 generatePair()
(只能从 Keystore 中检索到 public 密钥),我需要将其存储在不同的地方,以便即使应用程序被卸载也可以检索用户信息,因为每次后续调用到 generatePair()
将导致不同的密钥对。如果您知道解决此问题的不同方法,我非常欢迎您提供任何建议。
您从未从 public_key_text
尝试
char * public_key_text;
...
BIO_get_mem_data(bp_public, &public_key_text);
...
env->SetObjectArrayElement(returnPair, 0, env->NewStringUTF(public_key_text));