Analysis of string encryption and decryption using jni in android
Analysis of string encryption and decryption using jni in android
Recently, a demand for projects is to encrypt users' sensitive information, such as users' account passwords, mobile phone numbers, and other private information. In java, we can use the AES algorithm to encrypt and decrypt the string. The benefits of using the string do not need to be discussed, but we know that the android source code can be decompiled, therefore, AES encryption in pure Java mode is not secure. Therefore, we thought of using jni in android to encrypt and decrypt strings. so file, more importantly, it is implemented through C/C ++ code, so the security line is relatively high, it can be decompiled into machine code, but almost cannot be restored and decompiled, the following describes the encryption process in detail.
Considering that C/C ++ Code is fully used for string encryption and decryption, we need to consider the differences in data types on different system platforms. Here we recommend another method that is easy to implement, that is, the AES encryption and decryption logic in Java is used, and the core key required for AES encryption and decryption is put into C, and the required key is read from the static class library by calling jni, the specific implementation is as follows:
Project code structure:
AES algorithm logic in Java:
Publicclass SecurityUtil {
Privatestaticbyte [] keyValue;
Privatestaticbyte [] iv;
Privatestatic SecretKeykey;
Privatestatic AlgorithmParameterSpecparamSpec;
Privatestatic Cipherecipher;
Static {
System. loadLibrary ("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 (nosuchalgorithm1_tione ){
} Catch (nosuchpaddingeffectione ){
}
}
}
Publicstaticnativebyte [] getKeyValue ();
Publicstaticnativebyte [] getIv ();
Publicstatic String encode (Stringmsg ){
String str = "";
Try {
// Use the key and a set of algorithm parameters to initialize the cipher
Ecipher. init (Cipher. ENCRYPT_MODE, key, paramSpec );
// Encrypt and convert to a hexadecimal string
Str = asHex (ecipher. doFinal (msg. getBytes ()));
} Catch (badpaddingeffectione ){
} Catch (invalidkeypolictione ){
} Catch (invalidalgorithmparametergatetione ){
} Catch (illegalblocksizeeffectione ){
}
Returnstr;
}
Publicstatic String decode (Stringvalue ){
Try {
Ecipher. init (Cipher. DECRYPT_MODE, key, paramSpec );
Returnnew String (ecipher. doFinal (asBin (value )));
} Catch (badpaddingeffectione ){
} Catch (invalidkeypolictione ){
} Catch (invalidalgorithmparametergatetione ){
} Catch (illegalblocksizeeffectione ){
}
Return "";
}
Privatestatic String asHex (bytebuf []) {
StringBuffer strbuf = new StringBuffer (buf. length * 2 );
Inti;
For (I = 0; I
If (int) buf [I] & 0xff) <0x10) // Add zero before 10
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); // get the high byte
Intlow = Integer. parseInt (src. substring (I * 2 + 1, I * 2 + 2), 16); // get the lowest byte
Encrypted [I] = (byte) (high * 16 + low );
}
Returnencrypted;
}
How to read the key in 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;
}
How to call in android:
Publicclass MainActivityextends Activity {
Privatestaticfinal StringTAG = "MainActivity ";
Private StringencriptStr = "18721002361"; // encrypted string
@ Override
Protectedvoid onCreate (BundlesavedInstanceState ){
Super. onCreate (savedInstanceState );
SetContentView (R. layout. activity_main );
// After Encryption
String enstr = SecurityUtil. encode (encriptStr );
Log. d (TAG, "encrypted:" + enstr );
// After decryption
String destr = SecurityUtil. decode (enstr );
Log. d (TAG, "decrypted:" + destr );
}
}
Here, we use a mobile phone number as an example for encryption and decryption. The specific information can be viewed in the log, as shown below.
Comparison of encryption and decryption:
: Click here