如何在 jni 中使用 openssl return rsa 加密字符串
How to return rsa encrypted string using openssl in jni
在我的 android 应用程序中,我使用带有 JNI 的 openssl 库来加密数据。
在 C 程序中,我能够使用 RSA_public_encrypt() 成功加密数据。但是我无法使用
return 字符串
return (*env)->NewStringUTF(env, encryptedData);
我收到以下错误。
JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0x5c.
JNIEXPORT jstring JNICALL Java_com_jni_JniLayer_PublicEncryption
(JNIEnv *env, jobject thisObj, jstring inData) {
__android_log_print(ANDROID_LOG_DEBUG, "Func", "---> %s \n", __func__);
const char *cData = (*env)->GetStringUTFChars(env, inData, NULL);
if( NULL == cData )
return (*env)->NewStringUTF(env, "NULL");
__android_log_print(ANDROID_LOG_DEBUG, "RSA", "The data to encrypt is : %s\n", cData);
RSA *rsa = NULL;
FILE *out = fopen("/sdcard/PublicKey", "r");
if( NULL == out )
{
__android_log_print(ANDROID_LOG_ERROR, "File", "Unable to Open file : PublicKey\n");
return (*env)->NewStringUTF(env, "NULL");
}
rsa = PEM_read_RSAPublicKey(out, NULL,NULL,NULL);
fclose(out);
//rsa = PEM_read_bio_RSA_PUBKEY(bioKey, &rsa, NULL, NULL);
if (NULL == rsa)
{
__android_log_print(ANDROID_LOG_ERROR, "File", "Unable to generate RSA struct from BioKey\n");
return (*env)->NewStringUTF(env, "NULL");
}
if(strlen(cData) > (RSA_size(rsa)-11) )
{
__android_log_print(ANDROID_LOG_ERROR, "RSA", "The data to be encrypted is more than maximum length of data to encrypt is : %d.\n",(RSA_size(rsa)-11));
return (*env)->NewStringUTF(env, "NULL");
}
unsigned char chEncryptedData[4098] = {};
int iResult = RSA_public_encrypt(strlen(cData), cData, chEncryptedData, rsa, RSA_PKCS1_PADDING);
(*env)->ReleaseStringUTFChars(env, inData, cData);
// If encryption fails, returns NULL string, else returns encrypted string
if(-1 == iResult)
{
char *chErrMsg = malloc(256);
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), chErrMsg);
__android_log_print(ANDROID_LOG_ERROR, "RSA", "The data Encryption failed due to the reason : %s\n", chErrMsg);
free(chErrMsg);
return (*env)->NewStringUTF(env, "NULL");
}
__android_log_print(ANDROID_LOG_DEBUG, "RSA", "The Encrypted data is : %s\n", chEncryptedData);
return (*env)->NewStringUTF(env, chEncryptedData);
}
问题是你没有区分字节和字符。在 Java 中,字节只是八位值,并且都是有效的。另一方面,字符是 Unicode 字符的 UTF-8 format 表示。现在大多数小于 127 的字节值表示一个 UTF-8 字符,但对于更大的值则不是这样。字符可以由多个字节组成,并且对于哪些序列构成有效字符有严格的规定。
如果您要加密一个值,则需要使用字节,因为不能保证您的加密会产生有效的字符序列。事实上,几乎可以肯定该序列将无效。
在我的 android 应用程序中,我使用带有 JNI 的 openssl 库来加密数据。 在 C 程序中,我能够使用 RSA_public_encrypt() 成功加密数据。但是我无法使用
return 字符串return (*env)->NewStringUTF(env, encryptedData);
我收到以下错误。
JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0x5c.
JNIEXPORT jstring JNICALL Java_com_jni_JniLayer_PublicEncryption
(JNIEnv *env, jobject thisObj, jstring inData) {
__android_log_print(ANDROID_LOG_DEBUG, "Func", "---> %s \n", __func__);
const char *cData = (*env)->GetStringUTFChars(env, inData, NULL);
if( NULL == cData )
return (*env)->NewStringUTF(env, "NULL");
__android_log_print(ANDROID_LOG_DEBUG, "RSA", "The data to encrypt is : %s\n", cData);
RSA *rsa = NULL;
FILE *out = fopen("/sdcard/PublicKey", "r");
if( NULL == out )
{
__android_log_print(ANDROID_LOG_ERROR, "File", "Unable to Open file : PublicKey\n");
return (*env)->NewStringUTF(env, "NULL");
}
rsa = PEM_read_RSAPublicKey(out, NULL,NULL,NULL);
fclose(out);
//rsa = PEM_read_bio_RSA_PUBKEY(bioKey, &rsa, NULL, NULL);
if (NULL == rsa)
{
__android_log_print(ANDROID_LOG_ERROR, "File", "Unable to generate RSA struct from BioKey\n");
return (*env)->NewStringUTF(env, "NULL");
}
if(strlen(cData) > (RSA_size(rsa)-11) )
{
__android_log_print(ANDROID_LOG_ERROR, "RSA", "The data to be encrypted is more than maximum length of data to encrypt is : %d.\n",(RSA_size(rsa)-11));
return (*env)->NewStringUTF(env, "NULL");
}
unsigned char chEncryptedData[4098] = {};
int iResult = RSA_public_encrypt(strlen(cData), cData, chEncryptedData, rsa, RSA_PKCS1_PADDING);
(*env)->ReleaseStringUTFChars(env, inData, cData);
// If encryption fails, returns NULL string, else returns encrypted string
if(-1 == iResult)
{
char *chErrMsg = malloc(256);
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), chErrMsg);
__android_log_print(ANDROID_LOG_ERROR, "RSA", "The data Encryption failed due to the reason : %s\n", chErrMsg);
free(chErrMsg);
return (*env)->NewStringUTF(env, "NULL");
}
__android_log_print(ANDROID_LOG_DEBUG, "RSA", "The Encrypted data is : %s\n", chEncryptedData);
return (*env)->NewStringUTF(env, chEncryptedData);
}
问题是你没有区分字节和字符。在 Java 中,字节只是八位值,并且都是有效的。另一方面,字符是 Unicode 字符的 UTF-8 format 表示。现在大多数小于 127 的字节值表示一个 UTF-8 字符,但对于更大的值则不是这样。字符可以由多个字节组成,并且对于哪些序列构成有效字符有严格的规定。
如果您要加密一个值,则需要使用字节,因为不能保证您的加密会产生有效的字符序列。事实上,几乎可以肯定该序列将无效。