Android加密 JNI NDK 验证签名和包名

本文介绍了如何在Android应用中使用NDK和JNI进行加密操作,并详细阐述了如何获取并验证应用的签名值,包括区分debug和release包的签名,以及处理编码问题。通过创建jni文件夹,编写C/C++代码,配置Android.mk和Application.mk,最后编译生成.so库文件,并将其导入到项目中。完整示例代码可在GitHub找到。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值