接口数据加密之MD5加密
- MD5 加密
- Java层加密
- Native层加密
- 签名校验
- 功能实现
- 1.MD5 加密的实现
- 2.签名校验
- 源码
MD5 加密
定义: 一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),MD5 加密之后是一个 32 位不可逆字符串
Java层加密
加密算法网上有一大堆,但是我不推荐用java来写加密,防止别人抓包,无法防止别人反编译或者调试,作用不大。
Native层加密
需要一定的C,C++基础 ,了解一定的NDK知识
但是还是无法防止别人反编译,因为ndk本身原因无法对方法进行混淆,只要匹配好包名和方法名照样在任何地方都可以调用,所以要加入 签名校验,后台配置App的包名和签名,才可以使用
签名校验
Native 层校验签名,保护一下 ,虽然不能说是百分比的安全,但是安全的级别大大的增强
功能实现
1.MD5 加密的实现
- 在网上找到的MD5加密的方法:md5.cpp md5.h
- 我这里就不贴代码了 一会把例子上传一下
- 直接上核心
/**
* @author li
* 版本:1.0
* 创建日期:2020/7/2 10
* 描述:
*/
public class MD5SignUtils {
static {
// 加载自己的库
System.loadLibrary("native-lib");
}
//实现方法 MD5加密
public static native String signParams(String params);
//签名校验
public static native void checkSignature(Context context);
}
接下来我们先MD5加密
首先我们在需要掉接口登录的时候先将数据加密 如
String s = MD5SignUtils.signParams("userName=HHHYYY&userPwd=123456");
直接调用native方法 ,接下来 我们在native-lib.cpp中进行实现
static char *MD5TITLE = "LIMD5";
using namespace std ;
extern "C"
JNIEXPORT jstring JNICALL
Java_com_li_md5sign_MD5SignUtils_signParams(JNIEnv *env, jclass clazz,jstring params_) {
//1.传过来的String转成char
const char *params = env->GetStringUTFChars(params_,0);
//打印log日志文件
__android_log_print(ANDROID_LOG_ERROR,"JNI_TAG","params_的值:%s",params);
//2.字符串前后做点手脚 (加盐)
string signature_str(params);
signature_str.insert(0,MD5TITLE);
//去掉后两位 可以根据自身情况任意修改方法
signature_str = signature_str.substr(0,signature_str.length()-2);
//3 MD5加密
MD5_CTX *ctx = new MD5_CTX();
MD5Init(ctx);
MD5Update(ctx, (unsigned char *) signature_str.c_str(), signature_str.length());
unsigned char digest[16] = {0};
MD5Final(digest,ctx);
//这里出现问题 在mac电脑上报错 可以初始化大点就没问题了
// char md5_str[128] = {0};
char md5_str[32] = {0};
for (int i = 0; i < 16;i++) {
sprintf(md5_str,"%02x",digest[i]);
}
//释放资源
env->ReleaseStringUTFChars(params_,params);
__android_log_print(ANDROID_LOG_ERROR,"JNI_TAG","md5_str的值:%s",md5_str);
//返回String
return env->NewStringUTF(md5_str);
}
加密基本完成 这个加密加盐可根据自身情况任意修改,生成的.so文件可以给后台进行调用 这样相同的规则下可保证自己的加密和后台的相同
2.签名校验
1.先用java代码获取到正式包下的签名
PackageInfo packageInfo = null;
try {
packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
Log.e("TAG",signatures[0].toCharsString());
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
2.在 native 层 校验
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//application 进行调用
MD5SignUtils.checkSignature(this);
}
}
static int is_verify = 0;
static char *PACKAGE_NAME = "com.li.md5sign";
static char *APP_SIGNATURE= "308202e4308201cc020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b30090603550406130255533020170d3230303431333035313432335a180f32303530303430363035313432335a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330820122300d06092a864886f70d01010105000382010f003082010a0282010100b3734ac8d1ecf7e30be02a75bdaae0fd98b044cb12e007405b815636a1aa83d868551740356ac33643ff9294dbf011569b2776be8e8a318de33a56cf50c9ac93dbabce53f64239dd21908a5d252e37fcd42e57a3a6bad84f5b7eafb268038e3645c3d32c4a985731be3d4ed0a26ecbf46ab2d0b3d0d4910d75a5261f161aa438f2b7f14449a6044ca396620ad9351b0ec9cf560d16c771b3a3214124fd933ddeb6325a906de07ad914c9a084f47594d60e749aceca6e8be1e4e343e75cc62d36bdf7a27690f58103b65934a0d9f83875503e3dcf2c09c8db2ead37818b176d59b0ff5c73cd26af6a4ecf03fe21c38e460ad47bf36d0ae7669a8b38835d2f9e790203010001300d06092a864886f70d01010505000382010100148bf14237f11ac18c4ad0e66989794fb11f1b151c29b6c217b2b3e3d9d615a53b4dc2ea1b94d49cfe0aff7d4904a6c97846fd52972ecebf4100e5bd4999631c9d94540f4889a6122a8478510b907046f541ea0bd6b1d1c6a59583b03c91acbf9b1420630aa615177aa0ed34da508bf16be0893234d72d78570314df5c437f9c57184ce5cb93ee13ab2fa421da4e66215c3bd378aece0917a2f6f487c9453a22662d148aea11bc6f27ecda3489be4c86c738f03fb64200b9e0b11203a6acda227fb6d7dec3290c61400fa529431a6372ac46298f2937c8153c1677e884045d3cd63b31728de92c635807a594ea5e3faf036e66d9c4fb4ff17e30cd0913717500";
extern "C"
JNIEXPORT void JNICALL
Java_com_li_md5sign_MD5SignUtils_checkSignature(JNIEnv *env, jclass clazz, jobject context) {
// TODO: implement checkSignature()
//1 根据 this 获取包名
jclass j_clz = env->GetObjectClass(context);
jmethodID j_mid = env->GetMethodID(j_clz,"getPackageName","()Ljava/lang/String;");
jstring j_package_name = static_cast<jstring>(env->CallObjectMethod(context, j_mid));
//2 对比包名和自己的PACKAGE_NAME 是否一致
const char *c_package_name = env->GetStringUTFChars(j_package_name,NULL);
if(strcmp(c_package_name,PACKAGE_NAME)!=0){
return;
}
// 校验App的签名 这里根据java代码来写
//获取PackageManager
j_mid = env->GetMethodID(j_clz,"getPackageManager","()Landroid/content/pm/PackageManager;");
jobject j_package_manger = env->CallObjectMethod(context,j_mid);
//获取PackageInfo
j_clz = env->GetObjectClass(j_package_manger);
j_mid = env->GetMethodID(j_clz,"getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
jobject j_package_info = env->CallObjectMethod(j_package_manger,j_mid,j_package_name,0x00000040);
//获取Signature
j_clz = env->GetObjectClass(j_package_info);
jfieldID j_fid = env->GetFieldID(j_clz,"signatures","[Landroid/content/pm/Signature;");
jobjectArray j_signature = static_cast<jobjectArray>(env->GetObjectField(j_package_info,
j_fid));
//去第0个位置
jobject signature_first = env->GetObjectArrayElement(j_signature,0);
// 3.5 调用 signatures[0].toCharsString();
j_clz = env->GetObjectClass(signature_first);
j_mid = env->GetMethodID(j_clz,"toCharsString","()Ljava/lang/String;");
jstring j_signature_str = static_cast<jstring>(env->CallObjectMethod(signature_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","校验签名成功 :%s",c_signature_str);
is_verify = 1;
}
3 根据 0 或者是1 来判断是否是否进行加密
在执行1 之前先做判断
if (is_verify == 0) {
return env->NewStringUTF("error_signature");
}
基本上功能就实现了
源码