2

问题描述:调用函数时抛出NoSuchAlgorithmException

MessageDigest.getInstance("MD5");

在调用了一些我稍后会附上的 JNI 代码之后。

当我在真正的智能 Android 手机(Sony Ericsson X10i,Android 2.3.7)和 Android 模拟器(Android 2.3.3)上测试代码时,奇怪的事情发生了

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

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

估计是安卓版本的问题。但我不知道为什么调用顺序很重要(我对 JNI 代码中的 MessageDigest 没有做任何事情)。有人对这个问题有任何线索吗?

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

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

然后是 Jni 代码,用于获取签名的 .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;
}
4

0 回答 0