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