使用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);
}
}