2013-05-25 87 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