[英]Send string from C to Java using JNI
我正在嘗試使用JNI將字符串從C發送到Java。 這是我的C代碼:
static char* test_encrypt_ecb_verbose(char* plain_text_char, char* key_char, char** ciphertext)
{
uint8_t i, buf[64], buf2[64];
uint8_t key[16];
// 512bit text
uint8_t plain_text[64];
char outstr[64];
memcpy(key,key_char,16) ;
memcpy(plain_text, plain_text_char, 64);
memset(buf, 0, 64);
memset(buf2, 0, 64);
// print text to encrypt, key and IV
printf("ECB encrypt verbose:\n\n");
printf("plain text:\n");
for(i = (uint8_t) 0; i < (uint8_t) 4; ++i)
{
phex(plain_text + i * (uint8_t) 16);
}
printf("\n");
printf("key:\n");
phex(key);
printf("\n");
// print the resulting cipher as 4 x 16 byte strings
printf("ciphertext:\n");
for(i = 0; i < 4; ++i)
{
AES128_ECB_encrypt(plain_text + (i*16), key, buf+(i*16));
//phex(buf + (i * 16));
for (int j = 0; j < 16; ++j){
printf("%c", (buf + (i * 16))[j]);
}
printf("\n");
}
printf("\n\n decrypted text:\n");
for (i = 0; i < 4; ++i)
{
AES128_ECB_decrypt(buf + (i * 16), key, plain_text + (i * 16));
phex(plain_text + (i * 16));
}
printf("\n\n\n");
*ciphertext = malloc(64);
memcpy(*ciphertext, buf, 64);
return outstr;
JNIEXPORT jstring JNICALL Java_JniApp_test
(JNIEnv *env, jobject obj, jstring inputstr, jstring keystr){
const char *str;
const char *kstr;
char* encstr=NULL,estr;
str = (*env)->GetStringUTFChars(env,inputstr,NULL);
kstr = (*env)->GetStringUTFChars(env,keystr,NULL);
estr = test_encrypt_ecb_verbose(str,kstr,&encstr);
printf("---Start---\n");
//int b = test(num);
for (int j = 0; j < 64; ++j){
printf("%c",encstr[j]);
}
//printf("test: %c", *encstr);
return(*env)->NewStringUTF(env,encstr);
}
當我在返回到java之前打印encstr時,我得到了:
)?Ñi‰ªGÀ6Btílt〜,²#úK23Ej•)?
但是,當我將其發送到Java並打印時,我沒有得到相同的字符串。
這是我的Java文件:
public class JniApp {
public native String test(String inputstr, String keystr);
public static void main(String args[]){
JniApp ja = new JniApp();
String j = ja.test("1234567890abffff0987654321fedcba1234567890abffff0987654321fedcba","fred789lk6n2q7b1");
System.out.println("This is the cipher text\n"+j);
}
static
{
System.loadLibrary("editjnib");
}
}
我如何也可以在Java中獲得相同的字符串? 我有什么事做錯了嗎?
從邏輯上講,Java String
是Java char
的不可變序列,而Java char
又是無符號的16位整數,表示UTF-16代碼單元。 從邏輯GetStringUTFChars()
,JNI函數GetStringUTFChars()
將這樣的序列轉碼為JVM的內部字符串格式,該格式是一個以null終止的字節序列,其中包含字符串Java chars
的“修改UTF-8”編碼。
通過兩次調用GetStringUTFChars()
所做的工作本質上沒有任何錯誤。 實際上,對test_encrypt_ecb_verbose()
的調用也沒有內在的錯誤,但是您必須考慮結果的重要性問題。 如果要將其視為字符序列,那么它們的編碼是什么? 當然,假設結果是有效的[修改] UTF-8,這是不合理的。
根據系統的本地語言環境,結果字節序列可能是也可能不是有效的編碼字符字符串。 特別是,如果默認編碼為一字節編碼(例如ISO-8859-15 printf()
,則將其傳遞給printf()
可能會得到合理的結果,但否則,例如,當默認編碼為UTF-8時,嘗試打印無效字節序列時,取決於終端驅動程序。
類似地,JNI NewStringUTF()
函數期望字節序列包含字符序列的有效修改UTF-8編碼的字節,但同樣,您沒有提供一個。 沒有理由認為JNI所做的事情將以任何特定的方式與您的終端驅動程序所做的事情相關聯,並且期望能夠從生成的Java字符串中恢復編碼的字節是不合理的希望,我想您可能想對它解密。
我看到兩個主要的選擇:
將Java字符串明確編碼為byte[]
而不是另一個String。 已經完成了大部分工作,但是您需要更改本機方法的返回類型,並做一些工作以將結果包裝到Java byte[]
而不是嘗試將其放入String中。
執行字符編碼而不是字節編碼。 要正確執行此操作,最好的選擇是使用21位Unicode代碼點而不是(修改的)UTF-8代碼單元或UTF-16代碼單元。 這將意味着譯碼無論是從字符GetStringChars()
或修飾的UTF-8從字節GetStringUTFChars()
為代碼點序列(可能在形式int
陣列); 使用那些作為輸入的方式執行加密,以使結果每個字符不超過21位; 然后將結果重新編碼為UTF-16或修改后的UTF-8,然后再使用它們構造結果String
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.