目录
梗概
AES算法是对称加密算法的一种,所谓对称即加密和解密使用同一把密钥。对于AES算法的密钥长度有三种可供选择,分别是128、192、256,通常来说,密钥长度越长,安全级别越高。在这里介绍的ECB和CBC是AES加密算法的两种模式,前者是需要一个长度固定的密钥,且固定的明文会生成固定的密文。后者在前者的基础上添加一个动态随即参数IV,故对于相同的明文内容,每次加密都会生成不同的密文,更加安全。
ECB模式
1.加密流程:
(1)获取Cipher对象实例,需要传入算法、工作模式、填充模式
填充模式是指对于明文字节内容的填充,由于AES算法是一个分组加密算法,对于明文内容会按照指定的大小进行分组,但是,明文的长度并不一定刚好是指定大小的整数倍,那么对于最后一个分组,就需要进行数据填充,将分组填充至指定大小。
(2)初始化密钥对象,需要传入自定义密钥数组、加密算法
(3)使用密钥对象初始化Cipher对象,并设置加密模式Cipher.ENCRYPT_MODE
(4)传入明文,加密并返回结果
// 加密:
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// "恢复"秘钥对象
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// 初始化秘钥:设置加密模式ENCRYPT_
cipher.init(Cipher.ENCRYPT_MODE,keySpec);
// 加密
return cipher.doFinal(input);
}
2.解密流程
解密流程与加密流程大致相同,依然需要创建Cipher对象,密钥对象,不同的是在初始化密钥匙,需要将模式设置为解密模式Cipher.DECRYPT_MODE
// 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//恢复密钥
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// 初始化秘钥:设置解密模式DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE,keySpec);
// 解密
return cipher.doFinal(input);
}
3.测试方法
public static void main(String[] args) throws GeneralSecurityException {
// 原文:
String message = "天生我材必有用";
System.out.println("Message(原始信息): " + message);
// 128位密钥 = 16 bytes Key:
byte[] key = "1234567890abcdef".getBytes();
// 加密:
byte[] data = message.getBytes();
byte[] encrypted = encrypt(key, data);
System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(key, encrypted);
System.out.println("Decrypted(解密内容): " + new String(decrypted));
}
4.运行结果
CBC模式
1.加密流程
(3) CBC模式的加密流程前两步是一样,但前文提到过,CBC模式需要一个动态参数来提高安全性,因此在第3步需要生成一个16字节的动态随机数IV
(4)封装IvParameterSpec对象,该对象是用以指定IV的对象
(5)初始化密钥,传入参数加密模式Cipher.ENCRYPT_MODE,密钥对象以及IvParameterSpec对象
(6)加密,传入明文字节数组
(7)返回,IV不需要保密,把IV和密文一起返回
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 恢复秘钥对象
SecretKey keySpec=new SecretKeySpec(key,"AES");
// 生成一个16 bytes的initialization vector:
final SecureRandom secureRandom = SecureRandom.getInstanceStrong();
final byte[] iv = secureRandom.generateSeed(16);//16位动态随机数
System.out.println("动态随机数长度==>"+iv.length);
System.out.println("动态随机数==>"+Arrays.toString(iv));
//随机数封装成IvParameterSpec对象
final IvParameterSpec ivps = new IvParameterSpec(iv);
// 初始化秘钥
cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivps);
// 加密
final byte[] data = cipher.doFinal(input);
// 返回:
return join(iv,data);
}
//合并IV和密文
public static byte[] join(byte[] bs1, byte[] bs2) {
final byte[] bytes = new byte[bs1.length + bs2.length];
System.arraycopy(bs1,0,bytes,0,bs1.length);
System.arraycopy(bs2,0,bytes,bs1.length,bs2.length);
return bytes;
}
2.解密流程
(1)在加密后,解密结果和IV被封装在一个数组中返回,因此在解密前,需要分别获取密文和IV
(2)创建Cipher对象,密钥对象
(3)将IV重新封装为IvParameterSpec对象
(4)初始化密钥,传入参数 操作模式、秘钥、IV参数
(5)解密并返回结果
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 把input分割成IV和密文:
final byte[] iv = new byte[16];
final byte[] data = new byte[input.length - 16];
System.arraycopy(input,0,iv,0,16);
System.arraycopy(input,16,data,0,data.length);
System.out.println("iv==>"+Arrays.toString(iv));
// 解密:
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
final IvParameterSpec ivps = new IvParameterSpec(iv);
// 初始化秘钥
cipher.init(Cipher.DECRYPT_MODE,keySpec,ivps);
// 解密操作
return cipher.doFinal(data);
}
3.测试方法
// 原文:
String message = "碧云天,黄叶地,秋色连波,波上寒烟翠";
System.out.println("Message(原始信息): " + message);
// 256位密钥 = 32 bytes Key:
byte[] key = "qwerty34hjklmn567ghbc6sjutem0qh3".getBytes();
// 加密:
byte[] data = message.getBytes();
byte[] encrypted =encrypt(key,data);//调用加密函数
System.out.println("Encrypted(加密内容): " +
Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(key,encrypted);
System.out.println("Decrypted(解密内容): " + new String(decrypted));
}
4.运行结果