2

我正在尝试使用 JNI 在我的 Android Java 代码中使用一些编码 C 函数。

当我想返回编码的字符串时,使用

return (*env)->NewStringUTF(env, resultStr);

我明白了

08-15 13:36:43.787: W/dalvikvm(11302): JNI WARNING: input is not valid Modified UTF-8: illegal start byte 0x98
08-15 13:36:43.787: W/dalvikvm(11302):              string: '����.y�����s��a'
08-15 13:36:43.787: W/dalvikvm(11302):              in Lorg/wfmu/radio/MainActivity;.xteaBase64Encoding:(Ljava/lang/String;)[B (NewStringUTF)

我猜这是由于这个 xtea 算法。

那么如何将字符串传递给 Java,以及如何读取它呢?

爪哇代码

static {
    System.loadLibrary("mylib");
}

private native String xteaBase64Encoding(String str); 

...

String encodedPlaylistId = xteaBase64Encoding("somestring");

C代码

void charToUint32(char *string, uint32_t *block, unsigned int len)
{
        char *blockAsChar = (char *) block;

        for (int i = 0; i < len/4; ++i){
                  blockAsChar[i*4+3] = string[i*4];
                  blockAsChar[i*4+2] = string[i*4+1];
                  blockAsChar[i*4+1] = string[i*4+2];
                 blockAsChar[i*4] = string[i*4+3];
        }
}

void uint32ToChar(uint32_t *block, char *string, unsigned int len)
{
        char *blockAsChar = (char *) block;

        for (int i = 0; i < len/4; ++i){
                 string[i*4] = blockAsChar[i*4+3];
                 string[i*4+1] = blockAsChar[i*4+2];
                 string[i*4+2] = blockAsChar[i*4+1];
                 string[i*4+3] = blockAsChar[i*4];
        }
}

/*
 ** Translation Table as described in RFC1113
 */
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*
 ** encodeblock
 **
 ** encode 3 8-bit binary bytes as 4 '6-bit' characters
 */
void b64encodeblock( unsigned char in[3], unsigned char out[4], int len )
{
    out[0] = cb64[ in[0] >> 2 ];
    out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
    out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
    out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}


void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const k[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
    for (i=0; i < num_rounds; i++) {
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
        sum += delta;
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
    }
    v[0]=v0; v[1]=v1;
}


void xtea(uint32_t *v, uint32_t *k, unsigned int len) {
    for (int j = 0; j < len/8; ++j) {
        encipher(32, &v[j*2], k);
    }
}

jstring Java_***_MainActivity_xteaBase64Encoding(JNIEnv * env, jobject this, jstring javaStr)
{

    const char *str = (*env)->GetStringUTFChars(env, javaStr, 0);

    char *key = "abcdefghijklmnop";

    int modSize = strlen(str) % 8;

    int dataSize = strlen(str) + (modSize?(8 - modSize):0);

    char *sourceString = malloc(dataSize);

    memset(sourceString, 0, dataSize);
    memcpy(sourceString, str, strlen(str));
    uint32_t *dataBlock= (uint32_t *) malloc(dataSize);
    memset(dataBlock,0,dataSize);
    charToUint32(sourceString, dataBlock, dataSize);
    free(sourceString);

    (*env)->ReleaseStringUTFChars(env, javaStr, str);

    uint32_t *keyData= (uint32_t *) malloc(16);
    memset(keyData,0,16);
    charToUint32(key, keyData, 16);

    xtea(dataBlock,keyData,dataSize);

    char *resultStr = malloc(dataSize+1);
    memset(resultStr, 0, sizeof(dataSize+1));
    uint32ToChar(dataBlock, resultStr, dataSize);

    // Base64 encode the string
    int base64Size = (dataSize / 3 + ((dataSize % 3)?1:0)) * 4;

    char *base64Str = malloc(base64Size+1);
    memset(base64Str,0, base64Size+1);

    int j=0;
    int i = 0;
    int bytesRemaining = dataSize;
    while (bytesRemaining > 0){
        b64encodeblock((unsigned char *)&resultStr[j],(unsigned char *) &base64Str[i], bytesRemaining>3?3:bytesRemaining);
        bytesRemaining -= 3;
        j += 3;
        i += 4;
    }

    return (*env)->NewStringUTF(env, resultStr);
}
4

1 回答 1

3

我猜这是由于这个 xtea 算法

如果您尝试从加密数据创建字符串,请不要这样做。要么将其转换为 base64,要么将其作为字节数组传递给 Java 并在那里进行转换。

加密数据不是文本,不应在String.

The fact that your function is called xteaBase64Encoding suggests that you should be converting it to base64, too. Indeed, it looks like you're already trying to do base64 encoding - it may be that you just need to change this:

return (*env)->NewStringUTF(env, resultStr);

into

return (*env)->NewStringUTF(env, base64Str);

Currently you're not using base64Str after populating it...

(It's not clear why you're doing this in native code anyway - have you benchmarked and found that XTEA is too slow in Java?)

于 2013-08-15T05:50:44.090 回答