2011-08-13 34 views
8

我有在Java byte[],其報告其爲256個字節,其餘傳遞給一個本機函數中C.問題通過字節[]通過JNI至C在Android

當我試圖讓出的數據長度這個數組是完全錯誤的,當我將它打印出來時,它與我在將它傳遞給C之前打印出的數據不匹配。

我嘗試了幾種方法來訪問數據,包括GetByteArrayRegionGetByteArrayElements,但沒有任何東西給我我期望的數據。

正如我在研究這個,我試着看看JNI認爲jbyteArray的長度是GetArrayLength - 它報告的長度爲1079142960,遠遠超過我預期的256個字節。也值了每個函數被調用的時間是不同的,例如另一個時間GetArrayLength返回1079145720.

這裏是我用來訪問數組的代碼:

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

這似乎很直接,所以我我不確定發生了什麼事。這個數組在Java中看起來很好,但是它是在C中生成的,並且傳回來了,所以我認爲可能出現了錯誤,因爲Java不關心它,但是當它返回到C時會中斷陣列。

這裏是代碼我用來生成數組並將其傳回給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; 

我是否錯過了某些東西?

謝謝

+0

Java代碼是怎樣的? –

+0

Java中沒有什麼有趣的事情我從SharedPreferences對象中獲取字節數組,然後檢查數據和長度,這兩個數據看起來都不錯,然後將它傳遞給本機函數 –

回答

12

該函數原型不正確:

JNIEXPORT jbyteArray function(JNIEnv* env, jbyteArray array) 

第二個參數是任一jclassjobject。如果你的方法是靜態的,它應該是:

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

如果它不是靜態的:

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

你是治療類或對象的數組,這說明你得到意想不到的效果。

+0

這是問題所在。自從我在JNI做過任何工作以來,一直有一段時間,當我設置原型時,我忘了你必須這樣做。謝謝 –

0

嘗試附加'\ 0'字符的字符串。可能它無法識別字符串的結尾。

+0

它不是字符串它的結構 –

1

我假設主要的問題是你強制OpenSSL結構成一個字節數組。這個結構很可能會隨着時間的推移而被釋放。這將解釋返回給C時向您報告的奇怪和不同的長度。向Java輸出RSA*也不會對您有太大幫助 - Java對該特定結構沒有任何瞭解,並且無法識別它。

你應該嘗試使用的一個

  • i2d_PKCS8PrivateKey_bio(BIO * BP,EVP_PKEY * X,常量EVP_CIPHER * ENC,字符* KSTR,INT klen,pem_password_cb * CB,無效* U)
  • INT i2d_RSA_PUBKEY(RSA *一,無符號的字符** PP)

取決於你是否想僅僅通過公鑰信息或還有私人信息的Java(see also here)。這樣你就可以確保從一開始就處理一個字節數組。

一旦這適用於您(使用您已經嘗試過的技術),回到Java中,您可以將字節數組解析爲有意義的東西。這在公鑰密碼的情況下很簡單:在陣列中使用X509EncodedKeySpec,並使用KeyFactory#generatePublic生成公鑰。

事情在私鑰案件中稍微複雜一些。Java僅理解PKCS#8 format,而OpenSSL默認根據PKCS#1格式對其專用RSA密鑰進行編碼。但是您可以使用i2d_PKCS8PrivateKey_bio將密鑰轉換爲PKCS#8。你需要用你的RSA*EVP_PKEY*第一,雖然:

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

不加密的密鑰,並使用in-memory BIO,然後通過生成的字節數組到Java和那裏的PKCS8EncodedKeySpec構造,最後生成的與KeyFactory私鑰。