问题描述:调用函数时抛出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;
}