通過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:\Users\sodinochen\AppData\Local\Android\sdk\platforms
\android-16\android.jar;..\..\build\intermediates\classes\debug 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;
        }
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM