Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
331 views
in Technique[技术] by (71.8m points)

android - JNI DETECTED ERROR IN APPLICATION: use of invalid jobject when returning Array of String

Description of the intended goal

I'm trying to implement OpenSSL-generated public/private key pairs in Android/Kotlin using JNI, in order to implement user encryption on the information stored to the cloud server. I've compiled all OpenSSL source code and generated all .so files correcly.

The code (C++)

The C++ code to use OpenSSL is shown below. CmakeLists.txt and NDK configuration is working fine.

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: 
%s",public_key_text);
    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Private key is: 
%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;
    }
}

The error

If I check the Android Logcat, both public and private key seem to be generated correctly (as per __android_log_print output) but the app crashes with the following error when env->SetObjectArrayElement(returnPair, 0, public_key_text); is called:

JNI DETECTED ERROR IN APPLICATION: use of invalid jobject

The IDE (Android Studio) does not complain on any error, and the log suggests that key pair is being generated correctly, but I don't know why the keys are not being stored in the jobjectArray correctly. In fact, if I just simply put:

env->SetObjectArrayElement(returnPair, 0, env->NewStringUTF("Hello"));
env->SetObjectArrayElement(returnPair, 1, env->NewStringUTF("World"));

the code works completely fine, my Kotlin code gets the Strings correctly ("Hello" and "World"), and the app does not crash, which makes me think that problem is only on the C++ side.

The question

What I am doing wrong? I have checked other SO questions like JNI converting jstring to char * or jstring return in JNI program with slight modifications and combinations with no luck.

SIDE NOTE: I'm using OpenSSL implementation with C++ because Android/Kotlin code does not provide the private key generated using KeyPairGenerator.getInstance() and generatePair() (only public key can be retrieved from Keystore), which I need to be stored in a different place so that user information can be retrieved even if the app is uninstalled, as every subsequent call to generatePair() will lead to a different key pair. If you know a different approach to this problem I am more than welcome to any suggestions you may provide.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You never created a java string out of public_key_text

Try

char * public_key_text;
...
BIO_get_mem_data(bp_public, &public_key_text);
...
env->SetObjectArrayElement(returnPair, 0, env->NewStringUTF(public_key_text));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...