近些年DES使用越來越少,原因就在於其使用56位密鑰,比較容易被破解,近些年來逐漸被AES替代,AES已經變成目前對稱加密中最流行算法之一;
AES可以使用128、192、和256位密鑰,並且用128位分組加密和解密數據。本文就簡單介紹如何通過JAVA實現AES加密。
/**
* AES加密字符串
* @param content 需要被加密的字符串
* @param password 加密需要的密碼
* @return 密文
*/
public static String aesEncrypt(String content, byte [] password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 創建AES的Key生產者
kgen.init(128, new SecureRandom(password));// 利用用戶密碼作為隨機數初始化出
// 128位的key生產者
//加密沒關系,SecureRandom是生成安全隨機數序列,password.getBytes()是種子,只要種子相同,序列就一樣,所以解密只要有password就行
SecretKey secretKey = kgen.generateKey();// 根據用戶密碼,生成一個密鑰
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本編碼格式的密鑰,如果此密鑰不支持編碼,則返回// null。
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 轉換為AES專用密鑰
Cipher cipher = Cipher.getInstance("AES");// 創建密碼器
byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化為加密模式的密碼器
byte[] result = cipher.doFinal(byteContent);// 加密
return Base64.getEncoder().encodeToString(result);//返回字節數據用Base64編碼,解密之前先用Base64解碼
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
注意:加密后的byte數組是不能強制轉換成字符串的,換言之:字符串和byte數組在這種情況下不是互逆的;要避免這種情況,可以考慮將二進制數據轉換成十六進制表示或者用Base64編碼成字符串表示;
/**
* 解密AES加密過的字符串
* @param content AES加密過過的內容
* @param password 加密時的密碼
* @return 明文
*/
public static String aesDecrypt(String content, byte [] password) {
try {
//base64解碼
byte [] message = Base64.getDecoder().decode(content);
KeyGenerator kgen = KeyGenerator.getInstance("AES");// 創建AES的Key生產者
kgen.init(128, new SecureRandom(password));
SecretKey secretKey = kgen.generateKey();// 根據用戶密碼,生成一個密鑰
byte[] enCodeFormat = secretKey.getEncoded();// 返回基本編碼格式的密鑰
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");// 轉換為AES專用密鑰
Cipher cipher = Cipher.getInstance("AES");// 創建密碼器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化為解密模式的密碼器
byte[] result = cipher.doFinal(message);
return new String(result,StandardCharsets.UTF_8); // 明文
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
另外一種加密方式
/**
* 加密
* @param content 需要加密的內容, 待加密內容的長度必須是16的倍數
* @param password 加密密碼, 密鑰必須是16位的
* @return
*/
public static byte[] encrypt2(String content, String password) {
try {
SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
這種加密方式有兩種限制:
1.密鑰必須是16位的
2.待加密內容的長度必須是16的倍數,如果不是16的倍數,就會出如下異常:
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
at com.sun.crypto.provider.SunJCE_f.a(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
要解決如上異常,可以通過補全傳入加密內容等方式進行避免。