【发布时间】:2021-04-06 22:15:59
【问题描述】:
预期目标的描述
我正在尝试使用 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 converting jstring to char * 或 jstring return in JNI program,稍作修改和组合,但没有运气。
旁注:我在 C++ 中使用 OpenSSL 实现,因为 Android/Kotlin 代码不提供使用 KeyPairGenerator.getInstance() 和 generatePair() 生成的私钥(只能从 Keystore 检索公钥),我需要将其存储在不同的位置,以便即使卸载应用程序也可以检索用户信息,因为随后每次调用 generatePair() 都会导致不同的密钥对。如果您知道解决此问题的不同方法,我非常欢迎您提供任何建议。
【问题讨论】:
标签: android c++ openssl android-ndk