• 通过Jni实现AES的CBC模式加密解密


           AES加密方式基本实现,出现一个问题就是代码的安全性。我们知道java层代码很容易被反编译,很有可能泄漏我们加密方式与密钥 内容,那我们该怎么办呢?我们可以使用c/c++实现加密,编译成So库的形式,可供java实现调用,这样就大大增强程序安全性,因为so反编译结果是 arm指令,没有java中smali那么易懂。完全使用c/c++实现可能会比较麻烦,其实我们也可以简化一部分,只将密钥使用jni实现,其它还是用java实现,这样会简单一些,下面是具体操作;

    (1)新建项目aes

      在java类中添加native接口,注意写好native接口和System.loadLibrary()即可。代码如下:

    public synchronized static native String getFromNativeIv();
    
    public synchronized static native String getStringFromNative();

     (2)根据class文件生成相应的.h头文件,执行如下命令即可

    javah -d jni -classpath c:UserssodinochenAppDataLocalAndroidsdkplatforms
    android-16android.jar;....uildintermediatesclassesdebug com.aes.jniaes.MainActivity

     3)接下来在app module目录下的build.gradle中设置库文件名(生成的so文件名)。找到gradle文件的defaultConfig这项,在里面添加如下内容:

    defaultConfig {
            applicationId "com.aes.jniaes"
            minSdkVersion 15
            targetSdkVersion 22
            versionCode 1
            versionName "1.0"
    
            ndk {
                moduleName "aesjni"       //生成的so名字
                abiFilters "armeabi", "armeabi-v7a", "x86"   //输出指定三种abi体系结构下的so库。目前可有可无。
            }
        }

     (4)最后就是添加静态初始化loadLibrary代码,添加如下:

    static {
             System.loadLibrary("checkapp-jni");    //so文件的名字
           }

      (5)加密解密类AesUtil:

    public class AesUtils {
    
        // 加密
        public static String Encrypt(String sSrc, String sKey, String sIv) throws Exception {
            if (sKey == null) {
                System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.print("Key长度不是16位");
                return null;
            }
            byte[] raw = sKey.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// "算法/模式/补码方式"
            IvParameterSpec iv = new IvParameterSpec(sIv.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(sSrc.getBytes());
    
            String mm = new String(Base64.encode(encrypted, Base64.DEFAULT));
    
            return mm;// 此处使用BASE64做转码功能,同时能起到2次加密的作用。
        }
    
    
        // 解密
        public static String Decrypt(String sSrc, String sKey, String sIv) throws Exception {
            try {
                // 判断Key是否正确
                if (sKey == null) {
                    System.out.print("Key为空null");
                    return null;
                }
                // 判断Key是否为16位
                if (sKey.length() != 16) {
                    System.out.print("Key长度不是16位");
                    return null;
                }
                byte[] raw = sKey.getBytes("UTF-8");
                SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                IvParameterSpec iv = new IvParameterSpec(
                        sIv.getBytes());
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
                byte[] encrypted1 = Base64.decode(sSrc, Base64.DEFAULT);
                try {
                    byte[] original = cipher.doFinal(encrypted1);
                    String originalString = new String(original);
                    return originalString;
                } catch (Exception e) {
                    System.out.println(e.toString());
                    return null;
                }
            } catch (Exception ex) {
                System.out.println(ex.toString());
                return null;
            }
        }
    
    }
  • 相关阅读:
    【Java-算法】 计算十六进制校验位
    【Android-Zxing框架】二维码扫描框区域大小与不同手机分辨率适配问题
    【Android-开发环境】 eclipse开发环境搭建
    【Android-布局复用】 多个界面复用一个布局文件(二)
    【Android-布局复用】 多个界面复用一个布局文件(一)
    QQ群打卡脚本
    Linux CentOS 方舟生存进化开服教程[转]
    jwt认证

    drf
  • 原文地址:https://www.cnblogs.com/summers/p/4466209.html
Copyright © 2020-2023  润新知