只是一篇學習筆記,不系統。
嘗試用JNI進行AES加密
要求使用cbc算法、Pkcs5Padding填充、可自定義key、初始向量,嘗試一些庫,記錄下來。
從openssl中抽出的AES相關代碼 https://github.com/lcl101/AES_C
很多教程里提到了這個庫,應該是包含了比較完整的加密方式的,有時間再慢慢讀代碼。
一個用NDK實現AES加密、簽名校驗防止二次打包 https://github.com/BruceWind/AESJniEncrypt
這個庫應該是比較完善的,start的人也很多,但是目前僅支持ecb加密,也不支持自定義初始向量,只能先了解,等后續完善了。https://github.com/kokke/tiny-AES-c 是這個庫參考的算法,如果需要補全cbc加密等功能,應該可以在這個庫里找到。
https://github.com/panxw/android-aes-jni
是github上直接搜出來的庫,時間比較久遠應該也不維護了,把其中需要的代碼整理出來后,意外地很符合自己的需要,需要把256位密鑰改為128位,密鑰、初始向量也改為16位,另外C中的密鑰和向量都是16進制數組,而原java中是用字符串的,轉一下即可。
第二天發現有巨坑,他沒在C里寫解密算法!解密算法是用java實現的!
另一個實現比較臃腫沒細看 http://www.lxweimin.com/p/3f09a048a2cc
另有 https://github.com/wtuadn/JNITool 因為Base64加密錯誤的原因,一直以為是該代碼有問題,其實不然,應該也是能用的。
最后是在 https://github.com/xiangdingquan/Aes 找到比較符合我要求的第三方代碼。
第一個坑
java代碼里的base64加密Base64.encode(str, Base64.URL_SAFE),必須選擇URL_SAFE,不能選擇DEFAULT,否則會有部分特殊符號不一致。
第二個坑
加解密測試下來大多沒問題,但是在4.4系統中全部出錯,加密的時候傳入的字符串莫名短了很多。
extern "C"
JNIEXPORT jstring JNICALL
Java_com_zhaodaoweizhi_trackcar_g4_1jni_AESUtil_encrypt(JNIEnv *env, jclass type, jstring src_) {
const char *str = (char *) env->GetStringUTFChars(src_, 0);
env->ReleaseStringUTFChars(src_, str);
char *result = AES_CBC_PKCS7_Encrypt(str, AES_KEY, AES_IV);//AES CBC PKCS7Padding加密
jstring out = env->NewStringUTF(result);
return out;
}
這是加密的本地入口代碼,錯誤信息并沒有指向出錯源頭。為了找到源頭,只能進入加密算法里面,一行一行去打印日志,比對8.0系統下的正常日志。
最后發現是在char *result = AES_CBC_PKCS7_Encrypt(str, AES_KEY, AES_IV);
這個方法里報錯的,但奇怪的時候入口時str是正確的,在里面進一步計算的時候str就變短了。
沒有找到任何地方有修改過str,大膽猜測,是在前面那句env->ReleaseStringUTFChars(src_, str);
把str修改了,調換了這句代碼的位置再試試就通過了。
extern "C"
JNIEXPORT jstring JNICALL
Java_com_zhaodaoweizhi_trackcar_g4_1jni_AESUtil_encrypt(JNIEnv *env, jclass type, jstring src_) {
const char *str = (char *) env->GetStringUTFChars(src_, 0);
char *result = AES_CBC_PKCS7_Encrypt(str, AES_KEY, AES_IV);//AES CBC PKCS7Padding加密
env->ReleaseStringUTFChars(src_, str);
jstring out = env->NewStringUTF(result);
return out;
}
而這個問題只在4.4及以下系統下存在,其他系統并不報錯,非常奇怪了。