編輯:關於Android編程
android中使用jni對字符串加解密實現分析
最近項目有個需求,就是要對用戶的敏感信息進行加密處理,比如用戶的賬戶密碼,手機號等私密信息。在java中,就對字符串的加解密我們可以使用AES算法加密字符串,使用它的好處就不必多說了,但我們又知道android的源代碼是可以被反編譯的,所以使用純Java方式的AES加密是不安全的,所以想到了使用android中的jni來對字符串加解密處理,它會產生一個.so文件,更重要的是它通過C/C++代碼實現,所以安全行比較高,它可以被反編譯成機器碼,但幾乎不能被還原反編譯,那麼下面就詳細介紹下這種的加密處理。
鑒於完全使用C/C++代碼進行字符串的加解密,我們需要考慮不同系統平台上數據類型的差異問題,這裡推薦另一種易於實現的方法,即使用Java中的AES加解密邏輯,而將AES加解密所需要的核心秘鑰放入到C中,通過調用jni來從靜態類庫中讀取需要的秘鑰,具體實現如下:
項目代碼結構圖:
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+CkphdmHW0LXEQUVTy+O3qMLfvK2jujwvcD4KPHA+CnB1YmxpY2NsYXNzIFNlY3VyaXR5VXRpbCB7PC9wPgo8cD4KcHJpdmF0ZXN0YXRpY2J5dGVbXWtleVZhbHVlOzwvcD4KPHA+CjwvcD4KPHA+CiAgICBwcml2YXRlc3RhdGljYnl0ZVtdaXY7CiAgPC9wPgo8cD4KICAgIDwvcD4KPHA+CiAgICBwcml2YXRlc3RhdGljIFNlY3JldEtleWtleTsgCiAgICAgICAgICAgICAgICAgICAgICA8L3A+CjxwPgogICAgcHJpdmF0ZXN0YXRpYyBBbGdvcml0aG1QYXJhbWV0ZXJTcGVjcGFyYW1TcGVjOwogICAgPC9wPgo8cD4KICAgIHByaXZhdGVzdGF0aWMgQ2lwaGVyZWNpcGhlcjsKICAgICAgICAgICAgICAgICAgPC9wPgo8cD4KICAgICAgPC9wPgo8cD4KICAgIHN0YXRpYyB7PC9wPgo8cD4KICAgIFN5c3RlbS5sb2FkTGlicmFyeSg="cwtlib");
keyValue = getKeyValue();
iv = getIv();
if(null != keyValue &&
null !=iv) {
KeyGeneratorkgen;
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 (NoSuchAlgorithmExceptione) {
} catch (NoSuchPaddingExceptione) {
}
}
}
publicstaticnativebyte[] getKeyValue();
publicstaticnativebyte[] getIv();
publicstatic String encode(Stringmsg) {
String str ="";
try {
//用密鑰和一組算法參數初始化此 cipher
ecipher.init(Cipher.ENCRYPT_MODE,key,paramSpec);
//加密並轉換成16進制字符串
str = asHex(ecipher.doFinal(msg.getBytes()));
} catch (BadPaddingExceptione) {
} catch (InvalidKeyExceptione) {
} catch (InvalidAlgorithmParameterExceptione) {
} catch (IllegalBlockSizeExceptione) {
}
returnstr;
}
publicstatic String decode(Stringvalue) {
try {
ecipher.init(Cipher.DECRYPT_MODE,key,paramSpec);
returnnew String(ecipher.doFinal(asBin(value)));
} catch (BadPaddingExceptione) {
} catch (InvalidKeyExceptione) {
} catch (InvalidAlgorithmParameterExceptione) {
} catch (IllegalBlockSizeExceptione) {
}
return"";
}
privatestatic String asHex(bytebuf[]) {
StringBuffer strbuf =new StringBuffer(buf.length * 2);
inti;
for (i = 0;i
if (((int)buf[i]
& 0xff) < 0x10)//小於十前面補零
strbuf.append("0");
strbuf.append(Long.toString((int)buf[i]
& 0xff, 16));
}
returnstrbuf.toString();
}
privatestaticbyte[]
asBin(Stringsrc) {
if (src.length()
< 1)
returnnull;
byte[]encrypted
=newbyte[src.length()
/ 2];
for (inti
= 0;i
inthigh = Integer.parseInt(src.substring(i
* 2, i * 2 + 1), 16);//取高位字節
intlow = Integer.parseInt(src.substring(i
* 2 + 1, i * 2 + 2), 16);//取低位字節
encrypted[i]
= (byte) (high * 16 +low);
}
returnencrypted;
}
C中的讀取秘鑰的實現:
#include
#include"cwtlib.h"
constchar 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
};
constchar 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
{
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
{
bytes[i] = (jbyte)iv[i];
}
(*env)->SetByteArrayRegion(env,ivArray, 0,sizeof(iv), bytes);
(*env)->ReleaseByteArrayElements(env,ivArray,bytes,0);
return ivArray;
}
在android中如何調用:
publicclass MainActivityextends
Activity {
privatestaticfinal
StringTAG ="MainActivity";
private StringencriptStr
="18721002361";//加密的字符串
@Override
protectedvoid
onCreate(BundlesavedInstanceState) {
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)中進行討論。另外,原創作品來自不易,轉載請注明出處,謝謝。
最後附上原代碼供參考,下載地址:請點這裡
據說Android最推薦的是在ViewPager中使用FragMent,即ViewPager中的頁面不像前面那樣用LayoutInflater直接從布局文件加載,而是一個
1.PorterDuffXfermode這是由Tomas Proter和 Tom Duff命名的圖像轉換模式,它有16個枚舉值來控制Canvas上 上下兩個圖層的交互(先
簡介GreenDAO是一個開放的安卓代碼庫,來提供一個容易使用的SQLite數據庫接口,幫助開發者更加高效的處理數據——將開發者從處理低級的數據庫
ToDoList(fragment) 詳解 版權所有, 禁止轉載, 如有需要, 請站內聯系. Fragment(碎片) 可以靈活