• 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;
    	}
    	
    }
    
  • 相关阅读:
    HSV 量化
    小议:部署SharePoint 2013时,无法连接SQL Server问题
    BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包
    初识ASP.NET---一般处理程序
    Vue.js
    jQuery内部原理和实现方式浅析
    关于js中namespace命名空间模式
    MutationObserver 监听DOM树变化
    TCP/UDP常见端口参考
    运算符优先级
  • 原文地址:https://www.cnblogs.com/happyxiaoyu02/p/6818932.html
Copyright © 2020-2023  润新知