2013-08-15 2 views
1

J'essaie d'utiliser une fonction d'encodage C dans mon code Java Android en utilisant JNI.Comment passer la chaîne non utf-8 de la fonction JNI C à Java?

Quand je veux retourner la chaîne codée, en utilisant

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

Je reçois

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) 

que je suppose est due à cet algorithme XTEA.

Alors, comment puis-je passer la chaîne à Java, et comment puis-je la lire?

code java

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

private native String xteaBase64Encoding(String str); 

... 

String encodedPlaylistId = xteaBase64Encoding("somestring"); 

code 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[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"; 
/* 
** 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); 
} 
+0

Vous devez connaître le jeu de caractères et l'encodage que vous utilisez. Le cryptage et le recodage Base64 ne sont que des couches de transformation sur l'original. Le producteur et le consommateur de la chaîne doivent être d'accord sur les trois. Les chaînes Java sont Unicode. 'GetStringUTFChars' convertit une chaîne en un codage UTF-8 modifié à 0 terminé. 'NewStringUTF' l'inverse. À moins que le consommateur n'en soit conscient, il n'obtiendra pas le même résultat sur toute la gamme des caractères Unicode. Seules les bibliothèques associées à JNI comprennent le codage UTF-8 modifié. Autres bibliothèques _get par ** si ** les données sont un sous-ensemble Unicode. –

Répondre

2

que je suppose est due à cet algorithme XTEA

Si vous essayez de créer une chaîne de données cryptées, mais ne le font pas. Convertissez-le en base64 ou transmettez-le à Java en tant que tableau d'octets et effectuez la conversion.

données Encrypted est pas texte, et ne doit pas être représenté « brut » dans un String. Le fait que votre fonction s'appelle xteaBase64Encoding suggère que vous devriez aussi le convertir en base64. En effet, il semble que vous êtes déjà essayer coder en base64 - il se peut que vous avez juste besoin de changer ceci:

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

dans

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

vous êtes actuellement pas en utilisantbase64Str après peuplant ...

(on ne sait pas pourquoi vous faites cela dans le code natif de toute façon - avez-vous benchmarkée et a constaté que XTEA est trop lent en Java)

+0

Je devais évidemment passer base64Str, merci. J'ai essayé en Java mais je n'ai pas obtenu le même résultat que les exemples que mon client m'a transmis. Comme je ne voulais pas entrer dans l'algorithme, j'utilise son code, qui est le code C. – jul

+0

@jul: Hmm ... Je pense qu'il vaut la peine d'étudier pourquoi les résultats du chiffrement étaient différents. En utilisant le code du client, vous pouvez juste retarder la recherche d'un problème qui vous mordra plus tard. –

Questions connexes