Java 实现 AES 对称加密算法的加解密
前言
文章字数比较多,可直接查看代码:源码地址,文中描述有误的地方欢迎各位大神指导。
一、对称加密算法简介
1.对称加密
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
对称加密特点:
- 加密速度快,可以加密大文件。
- 密文可逆,一旦密钥文件泄漏,就会导致数据暴露。
- 加密后编码表找不到对应字符会出现乱码。
- 一般结合Base64使用。
2.加密模式
ECB
ECB(Electronic codebook):电子密码本,需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。
- 优点 : 可以并行处理数据。
- 缺点 : 同样的原文生成同样的密文,不能很好的保护数据。
CBC
CBC(Cipher-block chaining):密码块链接,每个明文块先与前一个密文块进行异或,然后再进行加密,在这种方法中,每个密文块都依赖于它前面的所有明文块。
- 优点 : 同样的原文生成的密文不一样。
- 缺点 : 串行处理数据。
3.填充模式
当需要按块处理的数据,数据长度不符合块处理需求时,按照一定的方法填充满块长的规则。
NoPadding
- 不填充,在AES加密算法下,要求原文长度必须是16byte的整数倍。
PKCS5Padding
- 数据块的大小为8位不够就补足。
二、AES 加解密代码实例
1.生成 AES 密钥
- AES 密钥长度默认只支持128、192、256 这三种长度,不合法的密钥长度程序会抛出异常。
- 生成 AES 密钥时会使用到随机数生成器,可以指定不同的随机数算法,也可以在创建随机数生成器时指定 seed。
- 初始化算法生成器时,如果不指定随机数生成器默认使用 new SecureRandom()。
代码如下:
public static SecretKey generateSecretKey(int keysize) throws NoSuchAlgorithmException {
// 校验密钥长度
if (keysize != 128 && keysize != 192 && keysize != 256) {
keysize = 128;
}
// 创建安全随机数生成器(SHA1PRNG)
final SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
// 创建 AES 算法生成器(AES)
final KeyGenerator generator = KeyGenerator.getInstance("AES");
// 初始化算法生成器
generator.init(keysize, random);
return generator.generateKey();
}
2.AES 加解密
代码如下:
public static void main(String[] args) throws Exception {
final String data = "test";
final SecretKey secretKey = generateSecretKey(128);
final byte[] encrypt = encrypt(secretKey.getEncoded(), data.getBytes());
final byte[] decrypt = decrypt(secretKey.getEncoded(), encrypt);
System.out.println(new String(decrypt));
}
/**
* AES 加密
*
* @param aseKey 密钥
* @param plain 加密原文
* @return 密文
*/
public static byte[] encrypt(byte[] aseKey, byte[] plain) throws Exception {
final SecretKey secretKey = new SecretKeySpec(aseKey, "AES");
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(plain);
}
/**
* AES 解密
*
* @param aseKey AES 密钥
* @param encrypted 解密密文
* @return 原文
*/
public static byte[] decrypt(byte[] aseKey, byte[] encrypted) throws Exception {
final SecretKey secretKey = new SecretKeySpec(aseKey, "AES");
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(encrypted);
}
3.AES + nonce 加解密
注意在使用 nonce 时,nonce 的长度不能超过 128,不然程序会抛出异常。
代码如下:
public static void main(String[] args) throws Exception {
final String data = "test";
final byte[] nonce = generatorNonce(16);
final SecretKey secretKey = generateSecretKey(128);
final byte[] encrypt = encrypt(secretKey.getEncoded(), data.getBytes(), nonce);
final byte[] decrypt = decrypt(secretKey.getEncoded(), encrypt, nonce);
System.out.println(new String(decrypt));
}
/**
* AES 加密
*
* @param aseKey AES 密钥
* @param plain 加密原文
* @param nonce 随机值
* @return 密文
*/
public static byte[] encrypt(byte[] aseKey, byte[] plain, byte[] nonce) throws Exception {
final SecretKey secretKeySpec = new SecretKeySpec(aseKey, "AES");
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
final GCMParameterSpec zeroIv = new GCMParameterSpec(128, nonce);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, zeroIv);
return cipher.doFinal(plain);
}
/**
* AES 解密
*
* @param aseKey AES 密钥
* @param encrypted 解密密文
* @param nonce 随机值
* @return 原文
*/
public static byte[] decrypt(byte[] aseKey, byte[] encrypted, byte[] nonce) throws Exception {
final SecretKeySpec secretKeySpec = new SecretKeySpec(aseKey, "AES");
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
final GCMParameterSpec zeroIv = new GCMParameterSpec(128, nonce);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, zeroIv);
return cipher.doFinal(encrypted);
}
/**
* 获取随机值
*
* @param len 随机值长度
*/
public static byte[] generatorNonce(int len) {
byte[] values = new byte[len];
final SecureRandom random = new SecureRandom();
random.nextBytes(values);
return values;
}