Android加密 JNI NDK 驗證簽名和包名

ndk的環境配置就不寫了,網上很多

首先新建一個項目,然後在包名下新建一個類,定義自己需要的native方法

public class SingatureClass {

    //驗證包名
    public native String verificationPackage(Object context); 

    //驗證簽名
    public native String verificationSign(Object context);
}

其次要獲取到項目的簽名值
這裏需要注意的地方是debug包和release包的簽名是不一樣的,如果要獲取release包的簽名值,則需要把該方法生成的簽名值先寫入本地日誌, 然後從日誌中獲取簽名值,將獲取到的簽名值複製到.c文件中

public static String getSignature(Context context) {
        try {
            /** 通過包管理器獲得指定包名包含簽名的包信息 **/
            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
            /******* 通過返回的包信息獲得簽名數組 *******/
            Signature[] signatures = packageInfo.signatures;
            /******* 循環遍歷簽名數組拼接應用簽名 *******/
            return signatures[0].toCharsString();
            /************** 得到應用簽名 **************/
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

接下來生成.h文件
打開Terminal,
輸入cd app/src/main/java,鍵入Enter
然後輸入javah -d ../jni -classpath . -jni 包名.類名
如果出現錯誤:“錯誤: 編碼GBK的不可映射字符”,
則輸入javah -d ../jni -classpath . -jni -encoding UTF-8 包名.類名

這裏寫圖片描述

在main目錄下新建jni文件夾,將生成的.h文件移動到jni目錄下
這裏寫圖片描述

然後在jni目錄先新建c/c++文件
將.h中的生成的方法複製到新建的c文件中,並且添加引用
將簽名值和包名進行賦值
下面貼出代碼

#include "com_lee_signatureencryption_SingatureClass.h"
#include <jni.h> 
#include <string.h>  
#include <unistd.h>  

/**
 * 發佈的app 簽名,只有和本簽名一致的app 纔會返回 AUTH_KEY
 * 這個RELEASE_SIGN的值是上一步用java代碼獲取的值
 */
const char* RELEASE_SIGN = "********92a864886f70d010";
const char* RELEASE_PACKAGE = "com.lee.signatureencryption";

JNIEXPORT jstring JNICALL Java_com_lee_signatureencryption_SingatureClass_verificationPackage
  (JNIEnv *env, jobject jobj, jobject context_object){

      jclass context_class = env->GetObjectClass(context_object);  

      //context.getPackageManager()  
      jmethodID methodId = env->GetMethodID(context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");  
      jobject package_manager_object = env->CallObjectMethod(context_object, methodId);  
      if (package_manager_object == NULL) {  

          return NULL;  
      }  

      //context.getPackageName()  
      methodId = env->GetMethodID(context_class, "getPackageName", "()Ljava/lang/String;");  
      jstring package_name_string = (jstring)env->CallObjectMethod(context_object, methodId);  
      if (package_name_string == NULL) {  

          return NULL;  
      }  

      const char* c_package = (char*)env->GetStringUTFChars(package_name_string, 0);
      if(strcmp(c_package, RELEASE_PACKAGE) == 0) {

          return (env)->NewStringUTF("package true");
      } else {

          return (env)->NewStringUTF("package error");
      }
  }



JNIEXPORT jstring JNICALL Java_com_lee_signatureencryption_SingatureClass_verificationSign
  (JNIEnv *env, jobject jobj, jobject context_object){

        jclass context_class = env->GetObjectClass(context_object);  

                //context.getPackageManager()  
                jmethodID methodId = env->GetMethodID(context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");  
                jobject package_manager_object = env->CallObjectMethod(context_object, methodId);  
                if (package_manager_object == NULL) {  
                    return NULL;  
                }  

                //context.getPackageName()  
                methodId = env->GetMethodID(context_class, "getPackageName", "()Ljava/lang/String;");  
                jstring package_name_string = (jstring)env->CallObjectMethod(context_object, methodId);  
                if (package_name_string == NULL) {  
                    return NULL;  
                }  

                env->DeleteLocalRef(context_class);  

                //PackageManager.getPackageInfo(Sting, int)  
                jclass pack_manager_class = env->GetObjectClass(package_manager_object);  
                methodId = env->GetMethodID(pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");  
                env->DeleteLocalRef(pack_manager_class);  
                jobject package_info_object = env->CallObjectMethod(package_manager_object, methodId, package_name_string, 64);  
                if (package_info_object == NULL) {  
                    return NULL;  
                }  

                env->DeleteLocalRef(package_manager_object);  

                //PackageInfo.signatures[0]  
                jclass package_info_class = env->GetObjectClass(package_info_object);  
                jfieldID fieldId = env->GetFieldID(package_info_class, "signatures", "[Landroid/content/pm/Signature;");  
                env->DeleteLocalRef(package_info_class);  
                jobjectArray signature_object_array = (jobjectArray)env->GetObjectField(package_info_object, fieldId);  
                if (signature_object_array == NULL) {  
                    return NULL;  
                }  
                jobject signature_object = env->GetObjectArrayElement(signature_object_array, 0);  

                env->DeleteLocalRef(package_info_object);  

                //Signature.toCharsString()  
                jclass signature_class = env->GetObjectClass(signature_object);  
                methodId = env->GetMethodID(signature_class, "toCharsString", "()Ljava/lang/String;");  
                env->DeleteLocalRef(signature_class);  
                jstring signature_string = (jstring) env->CallObjectMethod(signature_object, methodId);  

                const char* c_sign = (char*)env->GetStringUTFChars(signature_string, 0);

                //簽名一致  返回合法的 api key,否則返回錯誤
                if(strcmp(c_sign, RELEASE_SIGN)==0) {

                     return (env)->NewStringUTF("sign true");
                } else {

                  return (env)->NewStringUTF("sign error");

               }
  }

然後在jni 中添加Android.mk、Application.mk兩個文件
Android.mk

MY_LOCAL_PATH := $(call my-dir) 

include $(CLEAR_VARS)    

LOCAL_PATH := $(MY_LOCAL_PATH)

include $(CLEAR_VARS)    

LOCAL_MODULE := signature  
LOCAL_SRC_FILES := signature.cpp 
include $(BUILD_SHARED_LIBRARY)   

Application.mk

APP_ABI := all
APP_PLATFORM := android-14

在app 下的build.gradle中添加配置

android{

    ......

    sourceSets {
            main {
                jni.srcDirs = []
            }
        }
    repositories {
            flatDir {
                dirs 'libs'
            }
    }
}

打開Terminal
輸入 cd app/src/main/jni Enter
輸入 ndk-build
這裏寫圖片描述

等待幾分鐘時間,編譯成功後,將會生成libs和obj文件夾
libs中的文件就是我們需要的so
在main目錄下新建jniLibs文件夾,然後將libs中的文件全部拷貝到jniLibs中
這裏寫圖片描述

Demo地址:https://github.com/LeeVanie/SignatureEncryption

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章