调用JNI函数后的Android MessageDigest NoSuchAlgorithmException

时间:2013-07-26 09:15:03

标签: android exception cryptography java-native-interface

问题描述: 调用函数

时抛出NoSuchAlgorithmException
MessageDigest.getInstance("MD5");

在调用了一些JNI代码后,我将在稍后附上。

当我在真正的智能Android手机(索尼爱立信X10i,Android 2.3.7)和Android模拟器(Android 2.3.3)上测试代码时会发生奇怪的事情

如果我在JNI代码之前调用getInstance(..)函数,一切都很好。但是如果我首先运行JNI代码然后运行getInstance(..)函数,则抛出NoSuchAlgorithmException。

然而,这不是最奇怪的事情。如果我在Android模拟器(Android 4.2)中测试代码,无论我如何调用函数和JNI代码,一切都很好。

我猜这是Android版的问题。但我不知道为什么呼叫命令很重要 (我没有对JNI代码中的MessageDigest做任何事情)。有人对这个问题有什么线索吗?

我用于调用MessageDigest以获取某个文件的MD5哈希代码的代码:

            MessageDigest digest = null;
......
            try {
                digest = MessageDigest.getInstance("MD5");
                ........
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }

然后是Jni Code,它用于获取已签名的.apk文件的公钥。基本思想是使用JNI来调用Java方法。

    jobject getpackageManagerObject(JNIEnv *env, jobject context_object) {

    //Get class of Context Object
    jclass context_class = env->GetObjectClass(context_object);
    jmethodID methodId = env->GetMethodID(context_class, "getPackageManager",
                "()Landroid/content/pm/PackageManager;");
    jobject package_manager = env->CallObjectMethod(context_object, methodId);
    return package_manager;
    }  

    jobject getAllPackageInfo(JNIEnv* env, jobject package_manager_object) {

    //Get all installed packages Information, make a java call getInstalledPackages(...)
    jclass pack_manager_class = env->GetObjectClass(package_manager_object);
    jclass pack_manager_static_class = env->FindClass(
                    "android/content/pm/PackageManager");

    jfieldID field_signatures = env->GetStaticFieldID(pack_manager_static_class,
                    "GET_SIGNATURES", "I");
    int get_signatures_value = env->GetStaticIntField(pack_manager_static_class,
                    field_signatures);
    jmethodID methodId = NULL;
    methodId = env->GetMethodID(pack_manager_class, "getInstalledPackages",
                    "(I)Ljava/util/List;");
    jobject list_package_object = env->CallObjectMethod(package_manager_object,
                    methodId, get_signatures_value);
    return list_package_object;
    }

    jobject getIterator(JNIEnv* env, jobject list_package_object) {

    //make a java call to get List.Iterator()
    jclass list_class = env->GetObjectClass(list_package_object);
    jmethodID methodId = env->GetMethodID(list_class, "iterator",
                "()Ljava/util/Iterator;");
    jobject iterator = env->CallObjectMethod(list_package_object, methodId);
    return iterator;
    }

    JNIEXPORT jbyteArray JNICALL Java_com_jni_classes_JniClasses_getSign(
        JNIEnv *env, jclass jcl, jobject context_object,
        jstring str_package_name) {

    log_print("Call getSign()");
    log_print(env->GetStringUTFChars(str_package_name, NULL));

    jobject package_manager_object = NULL;
    package_manager_object = getpackageManagerObject(env, context_object);
    if (package_manager_object != NULL) {
        log_print("Get PackageManager Successfully!");
    } else {
        log_print("Get PackageManager Failed!");
        return NULL;
    }

    //Get all installed packages Information, make a java call getInstalledPackages(...)
    jobject list_package_object = NULL;
    list_package_object = getAllPackageInfo(env, package_manager_object);
    if (list_package_object != NULL) {
        log_print("Get All Package Info Successfully!");
    } else {
        log_print("Get Package Info Failed!");
        return NULL;
    }

    jobject iterator = getIterator(env, list_package_object);
    if (iterator != NULL) {
        log_print("Get iterator Successfully!");
    } else {
        log_print("Get iterator Failed!");
        return NULL;
    }

    //get the signature from the package
    jclass iterator_class = env->GetObjectClass(iterator);
    jmethodID methodId_for_hasNext = env->GetMethodID(iterator_class, "hasNext",
            "()Z");
    jmethodID methodId_for_next = env->GetMethodID(iterator_class, "next",
            "()Ljava/lang/Object;");

    /*if (methodId_for_next != NULL) {
    log_print("Get methodId_for_next Successfully!");
    } else {
    log_print("Get methodId_for_next Failed!");
    return NULL;
    }*/

    while (env->CallBooleanMethod(iterator, methodId_for_hasNext)) {
    jobject package_info = env->CallObjectMethod(iterator,
                methodId_for_next);
    jclass package_info_class = env->GetObjectClass(package_info);
    jfieldID fieldId_packageNname = env->GetFieldID(package_info_class,
                "packageName", "Ljava/lang/String;");
    jstring package_name = (jstring) env->GetObjectField(package_info,
                fieldId_packageNname);
    const char * c_package_name = env->GetStringUTFChars(package_name,NULL);
    const char * c_str_package_name = env->GetStringUTFChars(
                str_package_name, NULL);
    log_print("Start comparing ");
    log_print(c_package_name);

    //Two Package names is the same
    if (!strcmp(c_package_name, c_str_package_name)) {
    log_print("Same Package Name Found!!!");
    jfieldID field_package_signatures = env->GetFieldID(package_info_class,    
                            "signatures","[Landroid/content/pm/Signature;");
    if (field_package_signatures != NULL) {
        log_print("Get field_package_signatures Successfully!");
            } else {
                log_print("Get field_package_signatures Failed!");
                return NULL;
            }

        jobjectArray signature_array = NULL;
        signature_array = (jobjectArray) env->GetObjectField(package_info,
                    field_package_signatures);

        if (signature_array != NULL) {
            log_print("Get signature_array Successfully!");
        } else {
            log_print("Get signature_array Failed!");
            return NULL;
        }
        jobject signature_object = env->GetObjectArrayElement(
                    signature_array, 0);
        jclass signature_class = env->GetObjectClass(signature_object);
        jmethodID methodId_for_toByteArray = env->GetMethodID(
                    signature_class, "toByteArray", "()[B");
        jbyteArray signature_info = NULL;
        signature_info = (jbyteArray) env->CallObjectMethod(
                    signature_object, methodId_for_toByteArray);

        if (signature_info != NULL) {
            log_print("Get signature_info byte array Successfully!");
        } else {
            log_print("Get signature_info byte array Failed!");
            return NULL;
        }
        return signature_info;
    }

        env->DeleteLocalRef(package_info);
        env->DeleteLocalRef(package_info_class);

    }    
//don't find any package that matches str_package_name
    return NULL;
}

JNIEXPORT jstring JNICALL Java_com_jni_classes_JniClasses_getPublicKey(
        JNIEnv *env, jclass jcl, jbyteArray sig_bytes) {

    jclass cert_factory_class = env->FindClass(
            "java/security/cert/CertificateFactory");
    jmethodID methodId_getInstance = env->GetStaticMethodID(cert_factory_class,
            "getInstance",
            "(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;");
    jstring encode = env->NewStringUTF("X.509");
    jobject cert_factory_object = env->CallStaticObjectMethod(
            cert_factory_class, methodId_getInstance);
    jmethodID methodId_generateCertificate = env->GetMethodID(
            cert_factory_class, "generateCertificate",
            "(Ljava/io/InputStream;)Ljava/security/cert/Certificate;");

    //Get ByteArrayInputStream Object

    jclass byteArrayInputStream_class = env->FindClass(
            "java/io/ByteArrayInputStream");
    jmethodID methodId_constructor = env->GetMethodID(
            byteArrayInputStream_class, "<init>", "([B)V");
    jobject byteArrayInputStream_object = env->NewObject(
            byteArrayInputStream_class, methodId_constructor, sig_bytes);

   //Get X509Certificate Object

    jobject x509Certificate_object = env->CallObjectMethod(cert_factory_object,
            methodId_generateCertificate, byteArrayInputStream_object);

   //Get PublicKey

    jclass x509Certificate_class = env->GetObjectClass(x509Certificate_object);
    jmethodID methodId_getPublicKey = env->GetMethodID(x509Certificate_class,
            "getPublicKey", "()Ljava/security/PublicKey;");
    jobject publicKey_object = env->CallObjectMethod(x509Certificate_object,
            methodId_getPublicKey);
    jclass publicKey_class = env->GetObjectClass(publicKey_object);

    jmethodID methodId_toString = env->GetMethodID(publicKey_class, "toString",
            "()Ljava/lang/String;");
    jstring str_publicKey = (jstring) env->CallObjectMethod(publicKey_object,
            methodId_toString);
    return str_publicKey;
}

0 个答案:

没有答案