NDK开发-加密和签名校验

使用androidstudio的版本至少要是2.2以上。至于环境搭建,我就不阐述了,简书和博客有很多很不错的文章,大家可以参考下:https://www.jianshu.com/p/cb3064450688

签名第一步,程序运行起来,首先新建一个类SignatureUtils

public class SignatureUtils {
    static {
        System.loadLibrary("native-lib");
    }
    /**
     * native方法
     * @return
     */
    public static native String signatureParams(String params);
}

这里我们点击快捷键,alt+center选择创建方法即可

native-lib方法

 #include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring
JNICALL
Java_com_peakmain_ndk_SignatureUtils_signatureParams(JNIEnv *env, jclass type, jstring params_) {
    const char *params = env->GetStringUTFChars(params_, 0);
    env->ReleaseStringUTFChars(params_, params);
    return env->NewStringUTF("签名成功");
}

测试

 TextView tv = (TextView) findViewById(R.id.sample_text);
 //参数的加密应该是在运行时架构中 HttpUtils
 tv.setText(SignatureUtils.signatureParams("username=peakmain&userPwd=123456"));

Md5参数加密实现,首先需要下载md5的.h和.cpp文件

image.png

在cMakeLists.text文件中一定要添加src/main/cpp/md5.cpp,指定md5的cpp文件目录,否则会报错
image.png

修改native.lib

 #include <jni.h>
#include <string>

#include "md5.h"
 //额外附加的字符串
static char* EXTRE_SIGNATURE="Peakmain";
 using namespace std;
extern "C" JNIEXPORT jstring

JNICALL
Java_com_peakmain_ndk_SignatureUtils_signatureParams(JNIEnv *env, jclass type, jstring params_) {
    const char *params = env->GetStringUTFChars(params_, 0);

     //md5签名规则,加点料
    //1.字符串前面加点料
    string signature_str(params);
    signature_str.insert(0,EXTRE_SIGNATURE);
    //2.后面去掉两位
    signature_str=signature_str.substr(0,signature_str.length()-2);
    //3.md5加密,c++和java是一样的,唯一不同的是需要自己去回收内存
    MD5_CTX *ctx=new MD5_CTX();
    MD5Init(ctx) ;
    MD5Update(ctx,(unsigned char *)signature_str.c_str() ,signature_str.length());
    unsigned char digest[16];
    MD5Final(digest,ctx);
    //生成32位的字符串
    char md5_str[32];
    for(int i=0;i<16;i++){
        //不足的情况下补0
        sprintf(md5_str,"%s%02x",md5_str,digest[i]);
    }
    env->ReleaseStringUTFChars(params_, params);

    return env->NewStringUTF(md5_str);
}

效果图


image.png

app签名校验

首先我们用java的方法获取当前包名的签名

  PackageInfo packageInfo=null;
        try {
            packageInfo =getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        Signature[] signatures = packageInfo.signatures;
        Log.e("TAG",signatures[0].toCharsString());

修改native-lib

#include <jni.h>
#include <string>
#include <android/log.h>
#include "md5.h"

//额外附加的字符串
static char *EXTRA_SIGNATURE = "Peakmain";
//校验签名
static int is_verify = 0;
static char *PACKAGE_NAME = "com.peakmain.ndk";
static char *APP_SIGNATURE = "308201dd30820146020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b3009060355040613025553301e170d3138303531343033313130335a170d3438303530363033313130335a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330819f300d06092a864886f70d010101050003818d00308189028181008f8cbac9b66b6b347f0b183aa802b04cbb1a12d93f2824cf2451ca81482a72d925cd14215e15e02579e55e0e854b031bf3be81a3b73be87c0721c5e7dab4823769532bb6e5af15d42adbe163e53013479d54f7b849ce208c98e245fcd26ff6048683aa587468f4ddaad14d0b370f527044aabe0c161b2d66b512c07fbb7244470203010001300d06092a864886f70d01010505000381810023e6cc550111d86704b61189ebb04af4b5162dafb6f9974c74d8bd56bd8af279f48c44409bb32fd7c3aa880a5189a664a50c12ccf4f8a4ba5244944013c876bbd03c831b257df952d39d64a08e56585175817c787469b18973a33f7d1f21209b53ece8a554640c48d98c5714871e241cc2bc274e5bae5ff4c4d57c65db93e5b4";
using namespace std;
extern "C" JNIEXPORT jstring

JNICALL
Java_com_peakmain_ndk_SignatureUtils_signatureParams(JNIEnv *env, jclass type, jstring params_) {
    const char *params = env->GetStringUTFChars(params_, 0);
    if (is_verify == 0) {
        return env->NewStringUTF("error_signature");
    }
    //md5签名规则,加点料
    //1.字符串前面加点料
    string signature_str(params);
    signature_str.insert(0, EXTRA_SIGNATURE);
    //2.后面去掉两位
    signature_str = signature_str.substr(0, signature_str.length() - 2);
    //3.md5加密,c++和java是一样的,唯一不同的是需要自己去回收内存
    MD5_CTX *ctx = new MD5_CTX();
    MD5Init(ctx);
    MD5Update(ctx, (unsigned char *) signature_str.c_str(), signature_str.length());
    unsigned char digest[16];
    MD5Final(digest, ctx);
    //生成32位的字符串
    char md5_str[32];
    for (int i = 0; i < 16; i++) {
        //不足的情况下补0
        sprintf(md5_str, "%s%02x", md5_str, digest[i]);
    }
    env->ReleaseStringUTFChars(params_, params);

    return env->NewStringUTF(md5_str);
}
//c调用java
/**
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
return signatures[0].toCharsString();
 */
extern "C"
JNIEXPORT void JNICALL
Java_com_peakmain_ndk_SignatureUtils_signatureVerify(JNIEnv *env, jclass type, jobject context) {
    // 1. 获取包名
    jclass j_clz = env->GetObjectClass(context);
    jmethodID j_mid = env->GetMethodID(j_clz, "getPackageName", "()Ljava/lang/String;");
    jstring j_package_name = (jstring) env->CallObjectMethod(context, j_mid);
    // 2 . 比对包名是否一样
    const char *c_package_name = env->GetStringUTFChars(j_package_name, NULL);
    if (strcmp(c_package_name, PACKAGE_NAME) != 0) {
        return;
    }
    // 3. 获取签名
    // 3.1 获取 PackageManager
    j_mid = env->GetMethodID(j_clz,"getPackageManager","()Landroid/content/pm/PackageManager;");
    jobject pack_manager = env->CallObjectMethod(context,j_mid);
    // 3.2 获取 PackageInfo
    j_clz = env->GetObjectClass(pack_manager);
    j_mid = env->GetMethodID(j_clz,"getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    //后两个代表构造函数中的参数,0x00000040看 PackageManager.GET_SIGNATURES源码就可以知道了0x00000040==PackageManager.GET_SIGNATURES
    jobject package_info = env->CallObjectMethod(pack_manager,j_mid,j_package_name,0x00000040);
    // 3.3 获取 signatures 数组
    j_clz = env->GetObjectClass(package_info);
    jfieldID j_fid = env->GetFieldID(j_clz,"signatures","[Landroid/content/pm/Signature;");
    jobjectArray signatures = (jobjectArray) env->GetObjectField(package_info, j_fid);
    // 3.4 获取 signatures[0]
    jobject signatures_first = env->GetObjectArrayElement(signatures,0);
    // 3.5 调用 signatures[0].toCharsString();
    j_clz = env->GetObjectClass(signatures_first);
    j_mid = env->GetMethodID(j_clz,"toCharsString","()Ljava/lang/String;");
    jstring j_signature_str = (jstring) env->CallObjectMethod(signatures_first, j_mid);
    const char * c_signature_str = env->GetStringUTFChars(j_signature_str,NULL);
    // 4. 比对签名是否一样
    if (strcmp(c_signature_str, APP_SIGNATURE) != 0) {
        return;
    }
    __android_log_print(ANDROID_LOG_ERROR,"JNI_TAG","签名校验成功: %s",c_signature_str);
    // 签名认证成功
    is_verify = 1;
}
  

SignatureUtils工具类进行修改

public class SignatureUtils {
    static {
        System.loadLibrary("native-lib");
    }
    /**
     * native方法
     * @return
     */
    public static native String signatureParams(String params);

    /**
     * 校验签名
     * @param context
     * @return
     */

    public static native void signatureVerify(Context context);
}

Application中使用

public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        SignatureUtils.signatureVerify(this);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容