应用程序中的 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));