android 安全之——文件加密jni实现


上一篇提到了AES加密方式基本实现,这一篇我们不得提出一个问题,就是代码的安全性。我们知道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;
 }

 



本地方法声明:

public class JNIDeclaration {
	//AES Key
	public native byte[] getKeyValue();
	public native byte[] getIv();
	
}

 


java加解密实现:

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 调用测试:

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;
	}
	
}

 

posted @ 2014-10-27 22:51  HappyCode002  阅读(906)  评论(0编辑  收藏  举报