DES是Data Encryption Standard(数据加密标准)的缩写。它是由IBM公司研制的一种对称密码算法。DES是一个分组加密算法,典型的DES以64位(即8个字节)为分组对数据加密,加密和解密用的是同一个算法。它的密钥长度是56位(因为每个第8 位都用作奇偶校验),密钥可以是任意的56位的数,而且可以任意时候改变。
DES算法的安全性主要取决于密钥的保密。通常我们会自定义一串64位的密钥,并且直接将该密钥保存在java层,这中方式如果被他人反编译后极容易拿到我们的密钥,因此通常更好的做法时将密钥保存在jni层,这样会使得别人的破解难度加大,使得我们的程序更加安全,在jni中使用DES算法的方式通常可以使用c/c++重写DES算法,也可以直接在jni中通过反射来使用Android中的DES算法,本文中采用的是通过反射来使用Android中的DES算法的方式。
/**
* DES加密
*
* @param originalStr
* @return
*/
public static String encryptByDes(String originalStr) {
String result = null;
byte[] tmpOriginalStr = null;
try {
if (!TextUtils.isEmpty(originalStr)) {
tmpOriginalStr = originalStr.getBytes(CHARSET_NAME);
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance(ALGORITHM_DES);
// 创建一个DESKeySpec对象,KEY为自定义密钥常量
DESKeySpec dks = new DESKeySpec(KEY.getBytes());
// 将DESKeySpec对象转换成SecretKey对象
SecretKey secretKey = keyFactory.generateSecret(dks);
// 用密匙初始化Cipher对象
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
// Cipher对象实际完成加密操作
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 真正开始加密操作
byte[] tmpEncypt = cipher.doFinal(tmpOriginalStr);
if (tmpEncypt != null) {
result = Base64.encodeToString(tmpEncypt, Base64.NO_WRAP);
}
}
} catch (Exception e) {
Log.e("Erro", e.getMessage());
}
return result;
}
/***
* DES 解密
*
* @param desStr
* @return
*/
public static String decyptByDes(String desStr) {
String result = null;
try {
if (!TextUtils.isEmpty(desStr)) {
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance(ALGORITHM_DES);
// 创建一个DESKeySpec对象,KEY为自定义密钥常量
DESKeySpec dks = new DESKeySpec(KEY.getBytes());
// 将DESKeySpec对象转换成SecretKey对象
SecretKey secretKey = keyFactory.generateSecret(dks);
// 用密匙初始化Cipher对象
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
// Cipher对象实际完成解密操作
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// 真正开始解密操作
byte[] tmpDecypt = cipher.doFinal(Base64.decode(desStr,
Base64.NO_WRAP));
if (tmpDecypt != null) {
result = new String(tmpDecypt, CHARSET_NAME);
}
}
} catch (Exception e) {
Log.e("Erro", e.getMessage());
}
return result;
}
JNIEXPORT jstring JNICALL Java_EncryptionClient_encryptByDes
(JNIEnv *env, jclass clzz, jstring jstr) {
const char *des = "DES";
const char *desP = "DES/ECB/PKCS5Padding";
const char *charset = "UTF-8";
if (jstr != NULL && env->GetStringLength(jstr) > 0) {
jclass String = env->FindClass("java/lang/String");
jmethodID String_getBytes = env->GetMethodID(String, "getBytes",
"(Ljava/lang/String;)[B");
// 创建一个密匙工厂
jclass SecretKeyFactory = env->FindClass("javax/crypto/SecretKeyFactory");
jmethodID SecretKeyFactory_getInstance = env->GetStaticMethodID(SecretKeyFactory,
"getInstance",
"(Ljava/lang/String;)Ljavax/crypto/SecretKeyFactory;");
jobject keyFactory = env->CallStaticObjectMethod(SecretKeyFactory,
SecretKeyFactory_getInstance,
env->NewStringUTF(des));
// 创建一个DESKeySpec对象
jclass DESKeySpec = env->FindClass("javax/crypto/spec/DESKeySpec");
jmethodID DESKeySpec_init = env->GetMethodID(DESKeySpec, "", "([B)V");
// key为64位密钥
jbyte *by = (jbyte *) key;
jbyteArray keyByte = env->NewByteArray(64);
env->SetByteArrayRegion(keyByte, 0, 64, by);
jobject dks = env->NewObject(DESKeySpec, DESKeySpec_init, keyByte);
// 将DESKeySpec对象转换成SecretKey对象
jclass SecretKey = env->FindClass("javax/crypto/SecretKey");
jmethodID SecretKeyFactory_generateSecret = env->GetMethodID(SecretKeyFactory,
"generateSecret",
"(Ljava/security/spec/KeySpec;)Ljavax/crypto/SecretKey;");
jobject secretKey = env->CallObjectMethod(keyFactory, SecretKeyFactory_generateSecret,
dks);
// 用密匙初始化Cipher对象
jclass Cipher = env->FindClass("javax/crypto/Cipher");
jmethodID Cipher_getInstance = env->GetStaticMethodID(Cipher,
"getInstance",
"(Ljava/lang/String;)Ljavax/crypto/Cipher;");
jobject cipher = env->CallStaticObjectMethod(Cipher, Cipher_getInstance,
env->NewStringUTF(desP));
// Cipher对象实际完成加密操作
jmethodID Cipher_init = env->GetMethodID(Cipher, "init", "(ILjava/security/Key;)V");
env->CallVoidMethod(cipher, Cipher_init, 1, secretKey);
// 真正开始加密操作
jmethodID Cipher_doFinal = env->GetMethodID(Cipher, "doFinal", "([B)[B");
jbyteArray plainStringBytes = (jbyteArray) env->CallObjectMethod(jstr,
String_getBytes,
env->NewStringUTF(
charset));
jbyteArray encryptStr = (jbyteArray) env->CallObjectMethod(cipher, Cipher_doFinal,
plainStringBytes);
//释放对象
env->DeleteLocalRef(String);
env->DeleteLocalRef(SecretKeyFactory);
env->DeleteLocalRef(keyFactory);
env->DeleteLocalRef(DESKeySpec);
env->DeleteLocalRef(dks);
env->DeleteLocalRef(SecretKey);
env->DeleteLocalRef(Cipher);
env->DeleteLocalRef(keyByte);
env->DeleteLocalRef(plainStringBytes);
if (encryptStr != NULL) {
//Base64编码
jclass Base64 = env->FindClass("android/util/Base64");
jmethodID Base64_encode = env->GetStaticMethodID(Base64, "encodeToString",
"([BI)Ljava/lang/String;");
return (jstring) env->CallStaticObjectMethod(Base64, Base64_encode, encryptStr, 2);
}
}
return NULL;
}
JNIEXPORT jstring JNICALL Java_com_sensetime_encrypt_EncryptionClient_decryptByDes
(JNIEnv *env, jclass clzz, jstring jstr) {
const char *des = "DES";
const char *desP = "DES/ECB/PKCS5Padding";
const char *charset = "UTF-8";
if (jstr != NULL && env->GetStringLength(jstr) > 0) {
jclass String = env->FindClass("java/lang/String");
jmethodID String_getBytes = env->GetMethodID(String, "getBytes", "(Ljava/lang/String;)[B");
jmethodID String_init = env->GetMethodID(String, "", "([BLjava/lang/String;)V");
// 创建一个密匙工厂
jclass SecretKeyFactory = env->FindClass("javax/crypto/SecretKeyFactory");
jmethodID SecretKeyFactory_getInstance = env->GetStaticMethodID(SecretKeyFactory,
"getInstance",
"(Ljava/lang/String;)Ljavax/crypto/SecretKeyFactory;");
jobject keyFactory = env->CallStaticObjectMethod(SecretKeyFactory,
SecretKeyFactory_getInstance,
env->NewStringUTF(des));
// 创建一个DESKeySpec对象
jclass DESKeySpec = env->FindClass("javax/crypto/spec/DESKeySpec");
jmethodID DESKeySpec_init = env->GetMethodID(DESKeySpec, "", "([B)V");
jbyte *by = (jbyte *) key;
jbyteArray keyByte = env->NewByteArray(64);
env->SetByteArrayRegion(keyByte, 0, 64, by);
jobject dks = env->NewObject(DESKeySpec, DESKeySpec_init, keyByte);
// 将DESKeySpec对象转换成SecretKey对象
jclass SecretKey = env->FindClass("javax/crypto/SecretKey");
jmethodID SecretKeyFactory_generateSecret = env->GetMethodID(SecretKeyFactory,
"generateSecret",
"(Ljava/security/spec/KeySpec;)Ljavax/crypto/SecretKey;");
jobject secretKey = env->CallObjectMethod(keyFactory, SecretKeyFactory_generateSecret, dks);
// 用密匙初始化Cipher对象
jclass Cipher = env->FindClass("javax/crypto/Cipher");
jmethodID Cipher_getInstance = env->GetStaticMethodID(Cipher,
"getInstance",
"(Ljava/lang/String;)Ljavax/crypto/Cipher;");
jobject cipher = env->CallStaticObjectMethod(Cipher, Cipher_getInstance,
env->NewStringUTF(desP));
// Cipher对象实际完成解密操作
jmethodID Cipher_init = env->GetMethodID(Cipher, "init", "(ILjava/security/Key;)V");
env->CallVoidMethod(cipher, Cipher_init, 2, secretKey);
//Base64解码
jclass Base64 = env->FindClass("android/util/Base64");
jmethodID Base64_decode = env->GetStaticMethodID(Base64, "decode",
"(Ljava/lang/String;I)[B");
jbyteArray text = (jbyteArray) env->CallStaticObjectMethod(Base64, Base64_decode,
jstr, 2);
jstring decodeResult = NULL;
jthrowable exc = env->ExceptionOccurred();
if (exc) {
jclass newExcCls;
env->ExceptionDescribe();
env->ExceptionClear();
newExcCls = env->FindClass("java/lang/Exception");
env->ThrowNew(newExcCls, "please check input argument, str is not base64");
env->DeleteLocalRef(newExcCls);
} else {
// 真正开始解密操作
jmethodID Cipher_doFinal = env->GetMethodID(Cipher, "doFinal", "([B)[B");
jbyteArray decryptBytes = (jbyteArray) env->CallObjectMethod(cipher, Cipher_doFinal, text);
jthrowable exc = env->ExceptionOccurred();
if (exc) {
jclass newExcCls;
env->ExceptionDescribe();
env->ExceptionClear();
newExcCls = env->FindClass("java/lang/Exception");
env->ThrowNew(newExcCls, "please check input argument, last block incomplete in decryption");
env->DeleteLocalRef(newExcCls);
} else {
if (decryptBytes != NULL) {
decodeResult = (jstring) env->NewObject(String, String_init, decryptBytes,
env->NewStringUTF(charset));
}
}
}
//释放对象
env->DeleteLocalRef(SecretKeyFactory);
env->DeleteLocalRef(keyFactory);
env->DeleteLocalRef(DESKeySpec);
env->DeleteLocalRef(dks);
env->DeleteLocalRef(SecretKey);
env->DeleteLocalRef(Cipher);
env->DeleteLocalRef(keyByte);
env->DeleteLocalRef(Base64);
env->DeleteLocalRef(text);
return decodeResult;
}
return NULL;
}