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