我们知道java层代码很容易被反编译,很有可能泄漏我们加密方式与密钥内容,那我们该怎么办呢?我们可以使用c/c++实现加密,编译成So库的形式,可供java实现调用,这样就大大增强程序安全性,因为so反编译结果是arm指令,没有java中smali那么易懂。
完全使用c/c++实现可能会比较麻烦,其实我们也可以简化一部分,只将密钥使用jni实现,其它还是用java实现,这样会简单一些,下面是具体操作;
核心密钥jni实现:
- #include <jni.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- //导入日志头文件
- #include <android/log.h>
- const char keyValue[] = {
- 21, 25, 21, -45, 25, 98, -55, -45, 10, 35, -45, 35,
- 26, -5, 25, -65, -78, -99, 85, 45, -5, 10, -0, 11,
- -35, -48, -98, 65, -32, 14, -67, 25, 36, -56, -45, -5,
- 12, 15, 35, -15, 25, -14, 62, -25, 33, -45, 55, 12, -8,
- };
- const char iv[] = { //16 bit
- -33, 32, -25, 25, 35, -27, 55, -12, -15,32,
- 23, 45, -26, 32, 5,16
- };
- jbyteArray Java_com_xiaoyu_jnirelate_JNIDeclaration_getKeyValue(JNIEnv *env, jobject obj)
- {
- jbyteArray kvArray = (*env)->NewByteArray(env, sizeof(keyValue));
- jbyte *bytes = (*env)->GetByteArrayElements(env,kvArray,0);
- int i;
- for (i = 0; i < sizeof(keyValue);i++){
- bytes[i] = (jbyte)keyValue[i];
- }
- (*env)->SetByteArrayRegion(env,kvArray, 0, sizeof(keyValue),bytes);
- (*env)->ReleaseByteArrayElements(env,kvArray,bytes,0);
- return kvArray;
- }
- //JNIEXPORT JNICALL
- jbyteArray Java_com_xiaoyu_jnirelate_JNIDeclaration_getIv(JNIEnv *env, jobject obj)
- {
- jbyteArray ivArray = (*env)->NewByteArray(env, sizeof(iv));
- jbyte *bytes = (*env)->GetByteArrayElements(env,ivArray, 0);
- int i;
- for (i = 0; i < sizeof(iv); i++){
- bytes[i] = (jbyte)iv[i];
- }
- (*env)->SetByteArrayRegion(env,ivArray, 0, sizeof(iv), bytes);
- (*env)->ReleaseByteArrayElements(env,ivArray,bytes,0);
- return ivArray;
- }
本地方法声明:
- package com.xiaoyu.jnirelate;
- public class JNIDeclaration {
- //AES Key
- public native byte[] getKeyValue();
- public native byte[] getIv();
- }
java加解密实现:
- package com.xiaoyu.jnirelate;
- import java.security.InvalidAlgorithmParameterException;
- import java.security.InvalidKeyException;
- import java.security.spec.AlgorithmParameterSpec;
- import javax.crypto.BadPaddingException;
- import javax.crypto.Cipher;
- import javax.crypto.IllegalBlockSizeException;
- import javax.crypto.SecretKey;
- public class SecurityMag {
- private SecretKey key;
- private AlgorithmParameterSpec paramSpec;
- private Cipher cipher;
- public SecurityMag(SecretKey mkey,AlgorithmParameterSpec mparamSpec,Cipher mcipher){
- this.key=mkey;
- this.paramSpec=mparamSpec;
- this.cipher=mcipher;
- }
- public String encode(String msg) {
- String strHex = "";
- try {
- // 用密钥和一组算法参数初始化此 cipher
- cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
- // 对要加密的内容进行编码处理,
- strHex = byte2hex(cipher.doFinal(msg.getBytes()));
- } catch (BadPaddingException e) {
- e.printStackTrace();
- } catch (InvalidKeyException e) {
- e.printStackTrace();
- } catch (InvalidAlgorithmParameterException e) {
- e.printStackTrace();
- } catch (IllegalBlockSizeException e) {
- e.printStackTrace();
- }
- return strHex;
- }
- public String decode(String value) {
- String strContent="";
- try {
- cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
- // 对要解密的内容进行编码处理
- strContent = new String(cipher.doFinal(hex2byte(value)));
- } catch (BadPaddingException e) {
- e.printStackTrace();
- } catch (InvalidKeyException e) {
- e.printStackTrace();
- } catch (InvalidAlgorithmParameterException e) {
- e.printStackTrace();
- } catch (IllegalBlockSizeException e) {
- e.printStackTrace();
- }
- return strContent;
- }
- /**
- * 将二进制转化为16进制字符串
- *
- * @param b
- * 二进制字节数组
- * @return String
- */
- public String byte2hex(byte[] b) {
- String hs = "";
- String stmp = "";
- for (int n = 0; n < b.length; n++) {
- stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
- if (stmp.length() == 1) {
- hs = hs + "0" + stmp;
- } else {
- hs = hs + stmp;
- }
- }
- return hs.toUpperCase();
- }
- /**
- * 十六进制字符串转化为2进制
- *
- * @param hex
- * @return
- */
- public byte[] hex2byte(String hex) {
- byte[] ret = new byte[8];
- byte[] tmp = hex.getBytes();
- for (int i = 0; i < 8; i++) {
- ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
- }
- return ret;
- }
- /**
- * 将两个ASCII字符合成一个字节; 如:"EF"--> 0xEF
- *
- * @param src0
- * byte
- * @param src1
- * byte
- * @return byte
- */
- public byte uniteBytes(byte src0, byte src1) {
- byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))
- .byteValue();
- _b0 = (byte) (_b0 << 4);
- byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))
- .byteValue();
- byte ret = (byte) (_b0 ^ _b1);
- return ret;
- }
- }
android 调用测试:
- package com.xiaoyu.jnirelate;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- import javax.crypto.NoSuchPaddingException;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.IvParameterSpec;
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Log;
- public class TestActivity extends Activity {
- final String tag="TestActivity";
- private byte[] keyValue;
- private byte[] iv;
- private JNIDeclaration declaration_native;
- private SecurityMag secMag;
- static {
- System.loadLibrary("aeslib");
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- initKey();
- String mimi="hello are you good!";
- String encrypmimi=encryContent(mimi);
- decrypContent(encrypmimi);
- }
- private void initKey(){
- declaration_native=new JNIDeclaration();
- keyValue = declaration_native.getKeyValue();
- iv = declaration_native.getIv();
- if (null != keyValue && null != iv) {
- KeyGenerator kgen;
- try {
- kgen = KeyGenerator.getInstance("AES");
- kgen.init(128, new SecureRandom(keyValue));
- SecretKey key = kgen.generateKey();
- IvParameterSpec paramSpec = new IvParameterSpec(iv);
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- secMag=new SecurityMag(key,paramSpec,cipher);
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- } catch (NoSuchPaddingException e) {
- e.printStackTrace();
- }
- }
- }
- String encryContent(String str){
- String encrypStr=secMag.encode(str);
- Log.i(tag, "encryption content "+encrypStr);
- return encrypStr;
- }
- String decrypContent(String str){
- String decrypStr=secMag.decode(str);
- Log.i(tag, "encryption content "+decrypStr);
- return decrypStr;
- }
- }