最近在弄ndk,需要做一个用纯C校验签名的功能,也看了一些帖子,主要是参考下面两个:
主要思路是参考这个帖子,java代码和c代码都是,但是这个帖子里有几个小错误
http://blog.youkuaiyun.com/lgl1170860350/article/details/46348965
有的地方看了下这个帖:
http://blog.youkuaiyun.com/leifengpeng/article/details/52681196
因为同时用的是unity3D,没法传context参数给我,还顺便研究了下怎么获取context,参考贴:
http://blog.youkuaiyun.com/xiaogazhang/article/details/46891139
我的代码:
bool soulgameCheckMD5InPureC(jobject context,JNIEnv *env){
SGLOGD("soulgameCheckMD5InPureC() begin!");
//
jclass tem_class;
jmethodID tem_method;
jclass class_context = env->GetObjectClass(context);
//PackageInfo localPackageInfo = context.getPackageManager()
tem_method = env->GetMethodID(class_context, "getPackageManager", "()Landroid/content/pm/PackageManager;");
jobject obj_package_manager = env->CallObjectMethod(context, tem_method);
if(obj_package_manager == NULL){
SGLOGD("soulgameCheckMD5InPureC() getPackageManager failed!");
return false;
}
// getPackageName
tem_method = env->GetMethodID(class_context, "getPackageName", "()Ljava/lang/String;");
jobject obj_package_name = env->CallObjectMethod(context, tem_method);
env->DeleteLocalRef(class_context);
env->DeleteLocalRef(context);
if(obj_package_name == NULL){
SGLOGD("soulgameCheckMD5InPureC() getPackageName failed!");
return false;
}
// getPackageInfo
tem_class = env->GetObjectClass(obj_package_manager);
tem_method = env->GetMethodID(tem_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jobject obj_package_info = env->CallObjectMethod(obj_package_manager, tem_method, obj_package_name, 64);
env->DeleteLocalRef(obj_package_name);
env->DeleteLocalRef(obj_package_manager);
if(obj_package_info == NULL){
SGLOGD("soulgameCheckMD5InPureC() getPackageInfo failed!");
return false;
}
// Signature[] arrayOfSignature = localPackageInfo.signatures;
tem_class = env->GetObjectClass(obj_package_info);
jfieldID fieldID_signatures = env->GetFieldID(tem_class, "signatures", "[Landroid/content/pm/Signature;");
// Signature localSignature = arrayOfSignature[0];
jobject signatur = env->GetObjectField(obj_package_info, fieldID_signatures);
jobjectArray signatures = (jobjectArray)(signatur);
jobject signature = env->GetObjectArrayElement(signatures, 0);
env->DeleteLocalRef(signatures);
env->DeleteLocalRef(obj_package_info);
if(signatur == NULL){
SGLOGD("soulgameCheckMD5InPureC() signatures failed!");
return false;
}
// localSignature.toByteArray()
tem_class = env->GetObjectClass(signature);
tem_method = env->GetMethodID(tem_class, "toByteArray", "()[B");
jobject obj_sign_byte_array = env->CallObjectMethod(signature, tem_method);// 这个就是拿到的签名byte数组
env->DeleteLocalRef(signature);
env->DeleteLocalRef(tem_class);
if(obj_sign_byte_array == NULL){
SGLOGD("soulgameCheckMD5InPureC() toByteArray failed!");
return false;
}
// MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
jclass class_MessageDigest = env->FindClass( "java/security/MessageDigest");
tem_method = env->GetStaticMethodID( class_MessageDigest, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;");
jobject obj_md5 = env->CallStaticObjectMethod( class_MessageDigest, tem_method, env->NewStringUTF("md5"));
if(obj_md5 == NULL){
SGLOGD("soulgameCheckMD5InPureC() getInstance failed!");
return false;
}
// localMessageDigest.update(localSignature.toByteArray());
tem_method = env->GetMethodID(class_MessageDigest, "update", "([B)V");// 这个函数的返回值是void,写V
env->CallVoidMethod(obj_md5, tem_method, obj_sign_byte_array);
env->DeleteLocalRef(obj_sign_byte_array);
// localMessageDigest.digest()
tem_method = env->GetMethodID(class_MessageDigest, "digest", "()[B");
// 这个是md5以后的byte数组,现在只要将它转换成16进制字符串,就可以和之前的比较了
jbyteArray obj_array_sign = (jbyteArray)env->CallObjectMethod(obj_md5, tem_method);// jni中有强转类型的概念吗
env->DeleteLocalRef(obj_md5);
env->DeleteLocalRef(class_MessageDigest);
if(obj_array_sign == NULL){
SGLOGD("soulgameCheckMD5InPureC() digest failed!");
return false;
}
// 尝试用c写一下:http://blog.youkuaiyun.com/pingd/article/details/41945417
jsize int_array_length = env->GetArrayLength(obj_array_sign);
jbyte* byte_array_elements = env->GetByteArrayElements(obj_array_sign, NULL);
char* char_result = (char*) malloc(int_array_length*2+1);// 开始没有+1,在有的情况下会越界产生问题,还是在后面补上\0比较好
// 将byte数组转换成16进制字符串,发现这里不用强转,jbyte和unsigned char应该字节数是一样的
ByteToHexStr((unsigned char*)byte_array_elements, char_result, int_array_length);
*(char_result+int_array_length*2) = '\0';// 在末尾补\0
// jstring string_result = env->NewStringUTF(char_result);
// env->DeleteLocalRef(string_result);
// release
env->ReleaseByteArrayElements( obj_array_sign, byte_array_elements, JNI_ABORT);
env->DeleteLocalRef(obj_array_sign);
//校验
const char* pWhiteObject;
bool bIsMD5Right;
int nIndex = 0;
int nLen = sizeof(pMD5WhiteList)/4;
for(nIndex = 0;nIndex<nLen;nIndex++){
pWhiteObject = pMD5WhiteList[nIndex];
if( strcmp(char_result,pWhiteObject) == 0 ){
break;
}
}
if(nIndex<nLen){
bIsMD5Right = true;
}else{
bIsMD5Right = false;
}
// 释放指针使用free
free(char_result);
SGLOGD("soulgameCheckMD5InPureC() finish!");
if(bIsMD5Right){
return true;
}else{
return false;
}
}