android中使用jni对字符串加解密实现分析

android中使用jni对字符串加解密实现分析
最近项目有个需求,就是要对用户的敏感信息进行加密处理,比如用户的账户密码,手机号等私密信息。在java中,就对字符串的加解密我们可以使用AES算法加密字符串,使用它的好处就不必多说了,但我们又知道android的源代码是可以被反编译的,所以使用纯Java方式的AES加密是不安全的,所以想到了使用android中的jni来对字符串加解密处理,它会产生一个.so文件,更重要的是它通过C/C++代码实现,所以安全行比较高,它可以被反编译成机器码,但几乎不能被还原反编译,那么下面就详细介绍下这种的加密处理。
鉴于完全使用C/C++代码进行字符串的加解密,我们需要考虑不同系统平台上数据类型的差异问题,这里推荐另一种易于实现的方法,即使用Java中的AES加解密逻辑,而将AES加解密所需要的核心秘钥放入到C中,通过调用jni来从静态类库中读取需要的秘钥,具体实现如下:
 
项目代码结构图:
  Java中的AES算法逻辑:
public class SecurityUtil {
   private static byte[] keyValue;
   
    private static byte[] iv;  
    
    private static SecretKey key;                       
    private static AlgorithmParameterSpec paramSpec;    
    private static Cipher ecipher;                  
      
    static {
       System.loadLibrary("cwtlib");
       keyValue = getKeyValue();
       iv = getIv();
       
       if(null != keyValue && 
             null != iv) {
          KeyGenerator kgen;  
            try {  
                kgen = KeyGenerator.getInstance("AES");  
                // Java项目中的写法
                SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
                // Android项目中的写法
                SecureRandom random = SecureRandom.getInstance("SHA1PRNG","Crypto");
                
                random.setSeed(keyValue);
                kgen.init(128, random);  
                key = kgen.generateKey();  
                paramSpec = new IvParameterSpec(iv);  
                ecipher =    Cipher.getInstance("AES/CBC/PKCS5Padding");         
            } catch (NoSuchAlgorithmException e) {  
            } catch (NoSuchPaddingException e) {  
            }  
       }
    }  
    
    public static native byte[] getKeyValue();
    public static native byte[] getIv();
  
    public static String encode(String msg) {  
        String str = "";  
        try {             
            //用密钥和一组算法参数初始化此 cipher  
            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);  
            //加密并转换成16进制字符串  
            str = asHex(ecipher.doFinal(msg.getBytes()));  
        } catch (BadPaddingException e) {  
        } catch (InvalidKeyException e) {  
        } catch (InvalidAlgorithmParameterException e) {  
        } catch (IllegalBlockSizeException e) {  
        }  
        return str;  
    }  
      
    public static String decode(String value) {  
        try {  
            ecipher.init(Cipher.DECRYPT_MODE, key, paramSpec);  
            return new String(ecipher.doFinal(asBin(value)));  
        } catch (BadPaddingException e) {  
        } catch (InvalidKeyException e) {  
        } catch (InvalidAlgorithmParameterException e) {  
        } catch (IllegalBlockSizeException e) {  
        }  
        return "";  
    }  
  
    private static String asHex(byte buf[]) {  
        StringBuffer strbuf = new StringBuffer(buf.length * 2);  
        int i;  
        for (i = 0; i < buf.length; i++) {  
            if (((int) buf[i] & 0xff) < 0x10)//小于十前面补零  
                strbuf.append("0");  
            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));  
        }  
        return strbuf.toString();  
    }  
  
    private static byte[] asBin(String src) {  
        if (src.length() < 1)  
            return null;  
        byte[] encrypted = new byte[src.length() / 2];  
        for (int i = 0; i < src.length() / 2; i++) {  
            int high = Integer.parseInt(src.substring(i * 2, i * 2 + 1), 16);//取高位字节  
            int low = Integer.parseInt(src.substring(i * 2 + 1, i * 2 + 2), 16);//取低位字节  
            encrypted[i] = (byte) (high * 16 + low);  
        }  
        return encrypted;  
    }
 
C中的读取秘钥的实现:
#include <stdio.h>
#include "cwtlib.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[] =  {
   -33, 32, -25, 25, 35, -27, 55, -12, -15, 23, 45, -26, 32, 5 - 2, 74, 54
};
 
JNIEXPORT jbyteArray JNICALL Java_com_cwtlib_aesencript_SecurityUtil_getKeyValue
  (JNIEnv *env, jclass 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 jbyteArray JNICALL Java_com_cwtlib_aesencript_SecurityUtil_getIv
  (JNIEnv *env, jclass 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;
}
 
在android中如何调用:
public class MainActivity extends Activity {
   private static final String TAG = "MainActivity";
   
   private String encriptStr = "18721002361";     // 加密的字符串
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      
      // 加密后
      String enstr = SecurityUtil.encode(encriptStr);
      Log.d(TAG, "加密后:" + enstr);
      
      // 解密后
      String destr = SecurityUtil.decode(enstr);
      Log.d(TAG, "解密后:" + destr);
   }
}
这里以一个手机号为例进行加解密处理,具体的效果图可以在日志中查看到,具体如下。
加解密的对照效果图:
   
 
/**
* @auther david@cwteam
* 讨论:
*  Android技术讨论群(一):179914858
* 微博:
*  oschina: http://my.oschina.net/cwteam
*  csdn: http://blog.csdn.net/why_2012_gogo
/*


转载于:https://my.oschina.net/cwteam/blog/595419

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值