2013-05-25 89 views
-2

如何在JNI中實現這個函數?如何在JNI中實現

public byte[] decrypt(byte[] enc) throws Exception{ 
    Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding"); 
    SecretKeySpec myKey = new SecretKeySpec(key, "DESede"); 
    IvParameterSpec ivspec = new IvParameterSpec(initializationVector); 
    c3des.init(Cipher.DECRYPT_MODE, myKey, ivspec); 
    byte[] cipherText = c3des.doFinal(enc); 
    return cipherText; 
} 

我幾乎寫的所有方法,但我與最後兩行的一個問題:

jbyteArray Java_MainActivity_decrypt(JNIEnv* env, jobject context,jbyteArray key, jbyteArray iv, jbyteArray enc) { 


    //Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding"); 
    jclass cl = (*env)->FindClass(env,"javax/crypto/Cipher"); 
    jmethodID MID = (*env)->GetStaticMethodID(env,cl, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Cipher;"); 
    jstring s = (*env)->NewStringUTF(env,"DESede/CBC/PKCS5Padding"); 
    jobject c3des = (*env)->CallStaticObjectMethod(env,cl, MID, s); 

    //SecretKeySpec myKey = new SecretKeySpec(key, "DESede"); 
    jclass cl1 = (*env)->FindClass(env, "javax/crypto/spec/SecretKeySpec"); 
    jclass constructor1 = (*env)->GetMethodID(env, cl1, "<init>", "([BLjava/lang/String;)V"); 
    jstring s1 = (*env)->NewStringUTF(env,"DESede"); 
    jobject myKey = (*env)->NewObject(env, cl1, constructor1, key, s1); 

    //IvParameterSpec ivspec = new IvParameterSpec(initializationVector); 
    jclass cl2 = (*env)->FindClass(env, "javax/crypto/spec/IvParameterSpec"); 
    jclass constructor2 = (*env)->GetMethodID(env, cl2, "<init>", "([B)V"); 
    jobject ivspec = (*env)->NewObject(env, cl2, constructor2, iv); 

    //c3des.init(Cipher.DECRYPT_MODE, myKey, ivspec); 
    jmethodID mid_int = (*env)->GetMethodID(env, cl, "init","(ILjava/security/Key;Ljava/security/AlgorithmParameters;)V"); 
    jfieldID field_dec_id = (*env)->GetStaticFieldID(env, cl, "DECRYPT_MODE","I"); 
    jint field_dec = (*env)->GetStaticIntField(env, cl, field_dec_id); 
    (*env)->CallVoidMethod(env,c3des,mid_int,field_dec,myKey,ivspec); //<--app crash at this line 

    return; 
} 

應用程序崩潰的

(*env)->CallVoidMethod(env,c3des,mid_int,field_dec,myKey,ivspec); 

的myKey和ivspec都OK,我可以返回它們並在java中解密:

Cipher c3des = Cipher.getInstance("DESede/CBC/NoPadding"); 
c3des.init(Cipher.DECRYPT_MODE, myKey, ivspec); 
byte[] cipherText = c3des.doFinal(enc); 

在此先感謝

+1

既然你已經在Java中實現它,你問你怎麼可以從JNI調用它? –

+0

我想從上面寫的JNI訪問 – astar

+0

@TomBlodget:JNI用於兩個截然不同但相關的事情:1)從Java程序中調用本機代碼,2)從本機程序中調用Java代碼。看起來OP在詢問#2。 –

回答

1

您應該按照Android JNI tips頁面(即adb shell setprop debug.checkjni 1)的說明啓用擴展JNI檢查。或者您可以在已啓用CheckJNI功能的模擬器上運行您的代碼。通常情況下,啓用後,查看logcat輸出會給你一個JNI調用崩潰的確切原因。

而且,Java方法調用之間你應該做的:

if (env->ExceptionCheck()) { 
    // Optionally log something here. 
    return NULL; 
}

在這種特定的情況下,看來你用錯誤的函數原型爲Cipher#initIvParameterSpecAlgorithmParameterSpec的一個實例,而不是AlgorithmParameters,因此您需要使用原型(ILjava/security/Key;Ljava/security/spec/AlgorithmParameterSpec;)V代替。

+0

你是對的,錯誤的類型簽名,謝謝 – astar

+0

這裏帶走的教訓是「不要自己寫方法簽名」。使用'javap -s'的輸出。這絕不是錯的。 – EJP

+0

始終啓用CheckJNI。還有很多其他的錯誤可以使你不會崩潰應用程序(所有的時間),但是錯誤的。 – kroot