Android jni加密

咱们常常会有些敏感的信息须要客户端加解密,但android很容易被反编译,因此咱们写在客户端里的密钥终究得不到安全,可能有人会想把加密方式写在C代码中,生成.so供APK使用,但是别人不关心你C里的代码,直接把你的so文件给拿去用就能够了,那么有没有一种安全的措施来加大难度呢,我说一下咱们项目中若是解决客户端加密安全方案.java

首先加密的代码仍然写在C代码中,至少C被反编译出来是汇编代码,加大阅读难度,另一点就是如何让咱们的.so文件只容许在咱们本身的APK中使用,而不被别人拿去使用呢,这就须要签名验证这作一些文章,当程序调用.so时咱们能够C代码中检查当前程序的签名是否是咱们的,条件成立才进行加解密操做,固然签名泄露这个就另说了,毕竟没有百分百的安全,先来看看C代码 #include <string.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>android

//LOG宏定义
#define LOG_TAG "JNI_SCRIPT"
#define LOG_E(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, VA_ARGS)算法

jstring JNICALL
Java_com_example_administrator_myapplication_Test_getScriptData( JNIEnv* env,jobject obj, jobject contextObj){
//根据传入的context对象获取getApplicationContext(),防止java中获取其它已安装APK的Context对象
jclass context_cls = (*env)->GetObjectClass(env,contextObj);
jmethodID applicationContextMethod = (*env)->GetMethodID(env, context_cls, "getApplicationContext", "()Landroid/content/Context;");
jobject applicationContext = (*env)->CallObjectMethod(env, contextObj, applicationContextMethod);
if (applicationContext == NULL) {
LOG_E("context invalid!!");
}安全

char *st = "com.example.administrator.myapplication"; //当前程序包名  
//根据传入的context对象getPackageName  
jmethodID pkgName_method = (*env)->GetMethodID(env, context_cls, "getPackageName", "()Ljava/lang/String;");  
jstring pkgName = (*env)->CallObjectMethod(env, applicationContext, pkgName_method);  
char *pkg = (*env)->GetStringUTFChars(env, pkgName, NULL);  
//对比  
if (strcmp(st, pkg) != 0) {  
    LOG_E("package name invalid!!");  
    return NULL;  
}  

// 获取PackageManager对象  
jmethodID getPackageManager_method = (*env)->GetMethodID(env, context_cls, "getPackageManager", "()Landroid/content/pm/PackageManager;");  
jobject packageManager = (*env)->CallObjectMethod(env, applicationContext, getPackageManager_method);  

// PackageManager class  
jclass packageManager_cls = (*env)->GetObjectClass(env, packageManager);  

// 获得 getPackageInfo 方法  
jmethodID getPackageInfo_method = (*env)->GetMethodID(env, packageManager_cls,  
                                            "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");  

// 获取PackageInfo类对象  
jobject packageInfo = (*env)->CallObjectMethod(env, packageManager,  
                                               getPackageInfo_method, pkgName, 64);  

// 获取PackageInfo class  
jclass packageInfo_cls = (*env)->GetObjectClass(env, packageInfo);  
jfieldID signatures_field = (*env)->GetFieldID(env, packageInfo_cls, "signatures", "[Landroid/content/pm/Signature;");  
jobjectArray signatures = (*env)->GetObjectField(env, packageInfo, signatures_field);  
jobject signature = (*env)->GetObjectArrayElement(env, signatures, 0);  

jclass signature_cls = (*env)->GetObjectClass(env, signature);  
jmethodID hashcode_method = (*env)->GetMethodID(env, signature_cls, "hashCode", "()I");  
int hashCode = (*env)->CallIntMethod(env, signature, hashcode_method);  

// 检测apk签名的hashCode值,而后进行对比  
if (hashCode != -1370002482) {  
    LOG_E("apk signature error,don not use this .so !!")  
}  

//上面条件都经过后能够进行加密算法处理,加密代码省略  
//........  
return "加密后的字符串";

}
java中代码 [java] view plain copy public class Test {app

static{  
    System.loadLibrary("mylib");  
}  
public native String getScriptData(Context context);

}this

上面的C的代码中咱们从jni对API的反射来获取APK签名的hashCode值,第一步jni中接收Context对象,而后经过context对象获取getApplicationContext(),可能你会问我为何要这么作,其实这一步是为了防止在java层传入恶意的context对象,打个比方,咱们的程序叫A,恶意者的程序叫B,若是恶意者把A和B都安在手机中,那么在B程序中彻底能够获取A程序的Context对象,这样一旦把A程序的Context对象传入jni中,咱们的检测是经过的,恶意者是怎么可以在它的B程序中获取A程序的Context对象呢?下面一条语句就能够完成: [java] view plain copy Context thirdContext = createPackageContext("A程序的包名", Context.CONTEXT_IGNORE_SECURITY|Context.CONTEXT_INCLUDE_CODE);加密

是否是很容易,不过不用担忧,虽然在B程序中经过上面代码获取A的Context,但咱们只要用thirdContext.getApplicationContext()会返回null,因此咱们在调用jni中第一步就是先获取一下ApplicationContext对象code

第一步经过后,第二步获取当前程序的包名,进行对比,包名相同后接下来咱们就要获取so的调用者程序的签名了,这一步就是安全的关键性所在,若是以上条件都经过了,逻辑就到了咱们进行加解密的地方。对象

其实我在签名判断完后,又在安全性上作了一些小的手脚,好比判断咱们工程下某些java类是否是存在,这些类中某些方法是否是存在,这样及时签名被泄露后恶意者也要把项目中的一些类、方法所有如出一辙的保留才能使用咱们的.so库文件,又增长一些复杂度。安全没有十全十美,咱们能作的就是尽可能加大恶意者的破坏难度。ip