工作中遇到AES算法相关问题,进行一次记录,如有问题,欢迎大家指出~
AES算法
- 一种高级加密标准(英语:Advanced Encryption Standard,缩写:AES)在密码学中又称Rijndael加密法。
- 美国联邦政府采用的一种区块加密标准。
- 这个标准用来替代原先的DES。
- 是对称密钥加密中最流行的算法之一。
学习AES算法首先了解三个点:密钥、填充和模式。
密钥
实现加密和解密的基础,对明文的加密和解密需要同一个密钥。AES128,AES192,AES256,实际上就是指AES算法对不同长度密钥的使用,其中AES256安全性最高,AES128性能最高。
填充
AES算法在对明文进行加密是将明文拆分成一个个128bit明文块,当拆分时出现不满128bit时就需要进行填充。
Java中支持的两种填充:
- NoPadding:不做任何填充,但是要求明文必须是16字节的整数倍。
- PKCS5Padding(默认):如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。
模式
AES加密算法提供了五种不同的工作模式:ECB、CBC、CTR、CFB、OFB。
目前主要了解一下两种模式:
- ECB模式
ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。
优点:
- 简单;
- 有利于并行计算;
- 误差不会被传送;
缺点:
- 不能隐藏明文的模式;
- 可能对明文进行主动攻击;因此,此模式适于加密小消息
- CBC模式
优点:
- 不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
- 不利于并行计算;
- 误差传递;
- 需要初始化向量IV
Java的Cipher转换目前支持,括号中的键入:
- AES/CBC/NoPadding (128)
- AES/CBC/PKCS5Padding (128)
- AES/ECB/NoPadding (128)
- AES/ECB/PKCS5Padding (128)
AES/ECB/PKCS7Padding加密和解密
Java目前没有PKCS7Padding填充方式,需要在maven中添加bouncycastle依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.64</version>
</dependency>
具体实现方法:
public class EncryptUtils {
private static final String SECRET = "AES";
private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS7Padding";
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* AES加密ECB模式PKCS7Padding填充方式
* @param str 字符串
* @param key 密钥
* @return 加密字符串
* @throws Exception 异常信息
*/
public static String aes256ECBPkcs7PaddingEncrypt(String str, String key) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, SECRET));
byte[] doFinal = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
return new String(Base64.getEncoder().encode(doFinal));
}
/**
* AES解密ECB模式PKCS7Padding填充方式
* @param str 字符串
* @param key 密钥
* @return 解密字符串
* @throws Exception 异常信息
*/
public static String aes256ECBPkcs7PaddingDecrypt(String str, String key) throws Exception {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, SECRET));
byte[] doFinal = cipher.doFinal(Base64.getDecoder().decode(str));
return new String(doFinal);
}
}
测试:
public static void main(String[] args) throws Exception {
String str = "a1234567";
System.out.println("字符串:" + str);
String encryptStr = EncryptUtils.aes256ECBPkcs7PaddingEncrypt(str, "AES454-HTJSQ9-IT");
System.out.println("加密后字符串:" + encryptStr);
String decryptStr = EncryptUtils.aes256ECBPkcs7PaddingDecrypt(encryptStr, "AES454-HTJSQ9-IT");
System.out.println("解密后字符串:" + decryptStr);
}
运行结果:
加密字符串:a1234567
解密后字符串:OU/j67scNoiH8BVQLuMYBw==
解密后字符串:a1234567