java 与jni转码,使用JNI将字符串从C发送到Java

I am trying to send string from C to Java using JNI.

Here is my C code:

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);

}

When I print encstr before return back to java.. I get this:

)Ñi‰ªGÀ6Btílt˜,²#úK23Ej•)Ñi‰ªGÀ6Btílt˜,²#úK23Ej•

But when I send this to Java and print, I dont get the same string.

Here is my Java file:

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");

}

}

How can I get the same string in Java also? I there anything I am doing wrong?

解决方案

Java Strings are, logically, immutable sequences of Java chars, which in turn are unsigned, 16-bit integers representing UTF-16 code units. The JNI function GetStringUTFChars(), logically, transcodes such a sequence into the JVM's internal string format, which is a null-terminated sequence of bytes containing the "modified UTF-8" encoding of the Java chars of the string.

There's nothing inherently wrong with what you do up through the two calls to GetStringUTFChars(). In fact, there's nothing inherently wrong with the call to test_encrypt_ecb_verbose(), either, but you do have to consider the question of the significance of the result. If you want to treat it as a sequence of characters, then what is their encoding? Certainly it would be unreasonable to suppose that the result is valid [modified] UTF-8.

Depending on your system's native locale, the resulting byte sequence might or might not be a valid string of encoded characters. In particular, if the default encoding is a one-byte encoding such as ISO-8859-15 then you might get a reasonable gibberish result from passing it to printf(), but otherwise, such as when the default encoding is UTF-8, it's up to the terminal driver what to do with your invalid byte sequence when you try to print it.

Similarly, the JNI NewStringUTF() function expects the byte sequence to contain the bytes of a valid modified UTF-8 encoding of a character sequence, but again, you're not providing one. There is no reason to suppose that what JNI does with that will be correlated in any particular way with what your terminal driver did with it, and it would be unreasonably hopeful to expect to be able to recover the encoded bytes from the resulting Java String, which I suppose you might want to do to decrypt it.

I see two main alternatives:

Expressly encode the Java String to a byte[] rather than to another String. You're already most of the way there, but you'll need to change your native method's return type, and do a bit of work to pack the result into a Java byte[] instead of trying to put it into a String.

Perform a character-wise encoding instead of a byte-wise encoding. To do this properly, your best bet is to work in terms of 21-bit Unicode code points instead of either (modified) UTF-8 code units or UTF-16 code units. That would mean decoding either the chars from GetStringChars() or the modified UTF-8 bytes from GetStringUTFChars() into code point sequences (probably in the form of int arrays); performing your encryption using those as input, in such a way that the results do not require more than 21 bits per character; and then recoding the results into UTF-16 or modified UTF-8 before constructing the result String with them.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值