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");  

                kgen.init(128, new SecureRandom(keyValue));  

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

}

}

这里以一个手机号为例进行加解密处理,具体的效果图可以在日志中查看到,具体如下。

加解密的对照效果图:





好了,到这里我已经罗列出了所有主要文件实现,如果有问题可以在评论或是群(179914858)中进行讨论。另外,原创作品来自不易,转载请注明出处,谢谢。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。