最近做的聊天功能,老板希望对聊天的数据进行加密,然后存入数据库,首先想到的便是AES加密的方式,以前也用过几次,这次正好记录下来:
MD5加密是不可逆的,可以对用户的密码加密;
AES加密是可逆的,可以对数据库的数据进行加密,因为用户查询数据时,要返回明文,适合。
public class AESUtil {
private static String key= "123456";
/**
* 加密
* @param content待加密内容
* @param key 加密的密钥
* @return
*/
public static String encrypt(String content, String key) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");//构造密钥生成器,指定为AES算法,不区分大小写
kgen.init(128, new SecureRandom(key.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);//ENCRYPT_MODE指加密操作
byte[] byteRresult = cipher.doFinal(byteContent);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteRresult.length; i++) {
String hex = Integer.toHexString(byteRresult[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
* @param content 待解密内容
* @param key 解密的密钥
* @return
*/
public static String decrypt(String content, String key) {
if (content.length() < 1)
return null;
byte[] byteRresult = new byte[content.length() / 2];
for (int i = 0; i < content.length() / 2; i++) {
int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2),16);
byteRresult[i] = (byte) (high * 16 + low);
}
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key.getBytes());
kgen.init(128, secureRandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);//Decrypt_mode指解密操作
byte[] result = cipher.doFinal(byteRresult);
return new String(result,"utf-8");//不加utf-8,中文时会乱码
} 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 (Exception e) {
e.printStackTrace();
}
return null;
}
//重载的方法,使用默认密钥
public static String decrypt(String content) {
return decrypt(content, key);
}
public static String encrypt(String content) {
return encrypt(content, key);
}
遇到的问题:
1.javax.crypto.BadPaddingException: Given final block not properly padded
加密的密钥和解密的密钥不一致抛出该异常。
引用Stack Overflow:
If you try to decrypt PKCS5-padded data with the wrong key, and then unpad it (which is done by the Cipher class automatically), you most likely will get the BadPaddingException (with probably of slightly less than 255/256, around 99.61%), because the padding has a special structure which is validated during unpad and very few keys would produce a valid padding.
So, if you get this exception, catch it and treat it as “wrong key”.
2.含中文的数据加密后,进行解密会乱码
在解密的方法字节数组转字符串方法中,指明编码方式为UTF-8
3.在Windows系统中,上述代码没有问题。在linux下,报错javax.crypto.BadPaddingException,报错原因见https://blog.csdn.net/qq_23888451/article/details/94719836,即修改加密方法中kgen.init(128, new SecureRandom(key.getBytes()));这行代码为
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
kgen.init(128, random);