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 に渡すことができ、どのように読み取ることができるのでしょうか?

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、 .

関数が呼び出されるという事実は、xteaBase64Encodingそれも base64 に変換する必要があることを示唆しています。確かに、すでにbase64 エンコーディングを行おうとしているようです- これを変更する必要があるだけかもしれません:

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

の中へ

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

現在、入力後に使用し ていませんbase64Str...

(とにかくネイティブコードでこれを行っている理由は明らかではありません-ベンチマークを行って、XTEAがJavaで遅すぎることを発見しましたか?)

于 2013-08-15T05:50:44.090 に答える