1 前言
java开发中,加密还是一个非常常见的需求,常见的加密有对称加密和非对称加密两种,这两种使用的加密解密密钥方式不同。这里暂且不去讨论详细的加密原理。在java中AES加密用的比较多
2 AES对称加密
AES加密是一种对称加密,即加密和解密的密钥是相同的。在Android中,使用AES的加密如下:
/**
* @author Created by qiyei2015 on 2017/12/13.
* @version: 1.0
* @email: 1273482124@qq.com
* @description:
*/
public class AES {
private static final String TAG = AES.class.getSimpleName();
/**
* 生成SecretKey
* @param rules 生成规则
* @return
*/
private static SecretKeySpec generateSecretKey(String rules){
try {
//1.构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator keygen = KeyGenerator.getInstance("AES");
//2.根据规则初始化密钥生成器 生成一个128位的随机源,根据传入的字节数组
// 注意生成随机数的方式,否则在Android系统中可能会报错
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", new CryptoProvider());
secureRandom.setSeed(rules.getBytes("utf-8"));
keygen.init(128,secureRandom);
//3.产生原始对称密钥
SecretKey originalKey = keygen.generateKey();
//4.获得原始对称密钥的字节数组
byte [] raw = originalKey.getEncoded();
//5.根据字节数组生成AES密钥
SecretKeySpec key = new SecretKeySpec(raw, "AES");
return key;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* AES加密
* @param rules 规则
* @param plainText 明文
* @return 加密后的密文
*/
public static byte[] encrypt(String rules,String plainText){
if (TextUtils.isEmpty(rules)){
return null;
}
if (plainText == null || plainText.length() == 0){
return null;
}
try {
SecretKeySpec key = generateSecretKey(rules);
if (key != null){
//1.根据指定算法AES自成密码器
Cipher cipher = Cipher.getInstance("AES");
//2.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY
cipher.init(Cipher.ENCRYPT_MODE, key);
//3. 加密
byte [] byteEncode = cipher.doFinal(plainText.getBytes("utf-8"));
return byteEncode;
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* AES解密
* @param rules 规则
* @param encryptText 密文
* @return 解密后的明文
*/
public static byte[] decrypt(String rules,byte[] encryptText){
if (TextUtils.isEmpty(rules)){
return null;
}
if (encryptText == null || encryptText.length == 0){
return null;
}
try {
SecretKeySpec key = generateSecretKey(rules);
if (key != null){
//6.根据指定算法AES自成密码器
Cipher cipher = Cipher.getInstance("AES");
//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY
cipher.init(Cipher.DECRYPT_MODE, key);
//8. 解密
byte [] byteDecode = cipher.doFinal(encryptText);
return byteDecode;
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将二进制转换成16进制
* @param buffer 二进制数组
* @return 十六进制字符串
*/
public static String parseByte2HexStr(byte buffer[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buffer.length; i++) {
String hex = Integer.toHexString(buffer[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
* @param hexStr 十六进制字符串
* @return 二进制数组
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1){
return null;
}
byte[] result = new byte[hexStr.length()/2];
for (int i = 0;i< hexStr.length()/2; i++) {
int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
/**
* @author Created by qiyei2015 on 2017/12/16.
* @version: 1.0
* @email: 1273482124@qq.com
* @description:
*/
public class CryptoProvider extends Provider {
public CryptoProvider() {
super("Crypto", 1.0, "HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)");
put("SecureRandom.SHA1PRNG",
"org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl");
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
}
}
一般来说,我们都会将加密和解密的接口进行封装,因此封装的接口如下:
/**
* @author Created by qiyei2015 on 2017/12/13.
* @version: 1.0
* @email: 1273482124@qq.com
* @description: 加密Manager
*/
public class EncryptManager {
private static final String TAG = AES.class.getSimpleName();
/**
* 加密
* @param rules 加密规则
* @param plainText 加密前的明文
* @return 加密后的密文 16进制字符串
*/
public static String encrypt(String rules,String plainText){
if (TextUtils.isEmpty(plainText) || TextUtils.isEmpty(rules)){
return null;
}
byte[] encryptResult = AES.encrypt(rules,plainText);
if (encryptResult != null){
return AES.parseByte2HexStr(encryptResult);
}
return null;
}
/**
* 解密
* @param rules
* @param encryptText 加密后的密文 16进制字符串
* @return 加密前的明文
*/
public static String decrypt(String rules,String encryptText){
if (TextUtils.isEmpty(encryptText) || TextUtils.isEmpty(rules)){
return null;
}
byte[] decryptResult = AES.decrypt(rules,AES.parseHexStr2Byte(encryptText));
if (decryptResult != null){
try {
return new String(decryptResult,"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return null;
}
}
另外,在实际开发中需要对加密和解密的规则需要做特殊处理,防止反编译被发现等。如果是固定规则,可以考虑放在so库中,防止反编译。
3 加密示例
下面是一个AES加密和解密的示例:
public class EncryptActivity extends AppCompatActivity {
private EditText mEditTextRules;
private EditText mEditTextContent;
private TextView mTextViewResult;
private Button mButton1;
private Button mButton2;
String encryptResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_encrypt);
mEditTextRules = (EditText) findViewById(R.id.edt1);
mEditTextContent = (EditText) findViewById(R.id.edt2);
mTextViewResult = (TextView) findViewById(R.id.tv2);
mButton1 = (Button) findViewById(R.id.btn1);
mButton2 = (Button) findViewById(R.id.btn2);
mButton1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
encryptResult = EncryptManager.encrypt(mEditTextRules.getText().toString(),mEditTextContent.getText().toString());
mTextViewResult.setText("加密结果:" + encryptResult);
}
});
mButton2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String result = EncryptManager.decrypt(mEditTextRules.getText().toString(),encryptResult);
mTextViewResult.setText("加密结果:" + encryptResult
+ "\n\n" + "解密结果:" + result);
}
});
}
}
程序运行效果如下:
源代码参考:
https://github.com/qiyei2015/EssayJoke SDK encrypt部分