2011-08-13 2 views
8

J'ai un byte[] en Java qui présente sa longueur de 256 octets que je passe à une fonction native de C.octet de passage de problème [] via JNI à C sur Android

Quand j'ai essayé d'obtenir les données sur ce tableau était complètement faux et quand je l'ai imprimé, il ne correspondait pas aux données que j'ai imprimées juste avant de le transmettre à C.

J'ai essayé plusieurs façons d'accéder aux données, y compris à la fois GetByteArrayRegion et GetByteArrayElements mais rien ne semble pour me donner les données que j'attends.

Comme j'enquêtait sur ce que j'ai essayé de regarder ce JNI croyait que la longueur de jbyteArray était avec GetArrayLength - il a rapporté la longueur 1079142960, bien plus que les 256 octets I expected. De plus la valeur est différente chaque fois que la fonction a été appelée, par exemple une autre fois GetArrayLength retourné 1079145720.

Voici le code que je utilise pour accéder au tableau:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array) { 
    int length = (*env)->GetArrayLength(env, array); 

    jbyte data[256]; 

    (*env)->GetByteArrayRegion(env, array, 0, 256, data); 
    //also tried 
    //jbyte *data = (jbyte*) (*env)->GetByteArrayElements(env, array, NULL); 
} 

Cela semble assez simple pour que je Je ne suis pas vraiment sûr de ce qui se passe. Le tableau semble bien à partir de Java mais il a été généré en C et il est passé, donc je suppose que quelque chose aurait mal tourné ici que Java ne se soucie pas mais brise le tableau quand il revient à C.

Voici le code J'ai utilisé pour générer le tableau et renvoient la balle à Java:

//there is some openSSL stuff here that sets up a pointer to an RSA struct called keys that is size bytes large 

jbyteArray result = (*env)->NewByteArray(env, size); 

(*env)->SetByteArrayRegion(env, result, 0, size, (jbyte*)keys; 

Suis-je manque quelque chose?

Merci

+0

A quoi ressemble le code Java? –

+0

Rien d'intéressant ne se passe en Java J'attrape le tableau d'octets d'un objet SharedPreferences puis vérifie les données et la longueur qui paraissent bien, puis le passe à la fonction native –

Répondre

12

Ce prototype fonction est incorrect:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array) 

Le second argument est soit un jclass ou un jobject. Si votre méthode est statique, il devrait être:

JNIEXPORT jbyteArray function(JNIEnv* env, jclass cls, jbyteArray array) 

Et si ce n'est pas statique:

JNIEXPORT jbyteArray function(JNIEnv* env, jobject obj, jbyteArray array) 

Vous traitez la classe ou de l'objet comme un tableau, ce qui explique les résultats inattendus que vous obtenez.

+0

C'était le problème. Cela faisait longtemps que je n'avais pas travaillé sur JNI et lorsque j'ai mis en place le prototype, j'ai oublié que vous deviez le faire. Merci –

0

Essayez d'ajouter la chaîne avec le caractère '\ 0'. Probablement ce n'est pas capable d'identifier la fin de la chaîne.

+0

ce n'est pas une chaîne c'est une struct –

1

Je suppose que le problème principal est que vous forcez une structure OpenSSL dans un tableau d'octets. Très probablement cette structure sera libérée au fil du temps. Cela expliquerait les longueurs étranges et différentes qui vous sont rapportées lorsque vous revenez à C. Céder un RSA* à Java ne vous aidera pas non plus - Java n'a aucune connaissance de cette structure particulière et ne sera pas capable de le reconnaître .

Ce que vous devriez essayer est d'utiliser l'un des

  • i2d_PKCS8PrivateKey_bio (BIO * pb, EVP_PKEY * x, const EVP_CIPHER * enc, char * KSTR, int klen, pem_password_cb * cb, void * u)
  • int i2d_RSA_PUBKEY (RSA * a, unsigned char ** p)

selon que vous voulez transmettre uniquement les informations clé publique ou encore les informations privées à Java (see also here). De cette façon, vous pouvez être sûr de faire face à un tableau d'octets dès le début.

Une fois que cela fonctionne pour vous (en utilisant les techniques que vous avez déjà essayé), de retour en Java, vous pouvez analyser le tableau d'octets en quelque chose de significatif. Ceci est simple dans le cas de clé publique: Utilisez X509EncodedKeySpec avec votre tableau et générer une clé publique en utilisant KeyFactory#generatePublic.

Les choses sont légèrement plus compliquées dans le cas de la clé privée.Java ne comprend que le code PKCS#8 format tandis qu'OpenSSL code ses clés privées RSA selon le format PKCS # 1 par défaut. Mais vous pouvez déjà convertir votre clé en PKCS # 8 en utilisant i2d_PKCS8PrivateKey_bio. Vous avez besoin d'envelopper votre RSA* comme EVP_PKEY* d'abord, si:

EVP_pkey *pkey = EVP_PKEY_new(); 
EVP_PKEY_assign_RSA(pkey, rsa); 

Ne pas chiffrer votre clé et utiliser un in-memory BIO, puis passer le tableau d'octets résultant vers Java et là pour le constructeur de PKCS8EncodedKeySpec et enfin générer votre clé privée avec le KeyFactory.

Questions connexes