AES算法是对称加密中的算法之一,常用的对称加密算法(加密和解密使用同一个秘钥)还有DES,IDEA等。现在主流的算法是AES算法。
他们之间的区别如下:
算法 | 秘钥长度 | 工作模式 | 填充模式 |
DES | 56/64 | ECB/CBC..... | NoPadding......... |
AES(主流) | 128/192/256 | ECB/CBC...... | NoPadding/PKCS5Padding...... |
IDEA | 128 | ECB | PKCS5Padding...... |
AES有两种常用工作模式,分别是ECB和CBC。
注:工作模式不同,密钥的长度不同
CBC模式下允许出现随机内容
AES对长度有着绝对的要求
ECB工作模式
ECB模式下的加密过程:
ECB模式是最简单的模式,固定的明文生成固定的密文。
1、定义要加密的原文和秘钥
在ECB工作模式下,这里的秘钥是128位,16字节,且原文和秘钥均为字节数组类型的(getBytes)
2、进行真正的加密操作
(1)、创建加密对象:
Cipher cipher = Cipher.getInstance()
==>里面传入参数:A/B/C;算法名/工作模式/填充模式
(2)、根据字节内容(在上面的步骤定义的秘钥key),恢复秘钥对象
Secretkey sk = new Secretkey (A,B);
参数A:秘钥key 参数B:算法名
(3)、初始化秘钥并设置加密模式
cipher.init(A,B);
参数A:加密模式,Cipher类中定义的常量 参数B:恢复的秘钥对象(sk)
(4)、根据原文内容(字节形式)进行加密
Cipher.doFinal(A)
参数A:传入要加密的明文内容
实际代码案例:
// AES + ECB
public class AESDemon01 {
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));
}
// 加密:
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey secretKey = new SecretKeySpec(key, "AES");
// 初始化秘钥:设置加密模式ENCRYPT_
cipher.init(Cipher.ENCRYPT_MODE,secretKey );
// 根据原始内容(字节),进行加密
return cipher.doFinal(input);
// At7FZSwCFfk69p8Anw9tWA==
// a8MJCOSonzcdWEZ6suh6kLbiHdf5K1SQxuwZHrUJNdM=
}
}
解密过程:
解密过程的操作和加密过程完全一致,只是在最后做doFinal()操作时,将参数改为传入的已经加密的内容(密文,且是字节形式)
eg:
/ 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey secretKey = new SecretKeySpec(key, "AES");
// 初始化秘钥:设置解密模式DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// 根据原始内容(字节),进行解密
return cipher.doFinal(input);
}
CBC工作模式
在这种工作模式下会有一个随机数IV,相同的明文会产生不同的随机数不同,所以加密形成的密文也不同,这就使得安全性有了提高。
与EBC模式进行区别:
在加密的过程中,进行初始化时:
cipher.initiate(A,B,C);
参数A:加密模式 参数B:秘钥 参数C:IV参数
IV参数是在初始化之前进行定义的。具体过程如下:
(1)首先使用核心类库中的方法:
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] b= random.generateSeed(16);
这里是用random随机数产生的IV随机数,参数中的16代表生成16个字节的随机数。
(2)将随机数封装成 IvParameterSpec 对象
IvParameterSpec IV = new IvParameterSpec(b);
其他过程与流程与ECB模式的流程基本一致,CBC模式下的IV不需要保密,把IV随机数和密文一起返回。
注:CBC模式下的秘钥长度为256位,也就是32字节
具体代码案例如下:
public class AESCBCDemon {
public static void main(String[] args) throws Exception {
// 原文:
String message = "天动万象";
System.out.println("Message(原始信息): " + message);
// 256位密钥 = 32 bytes Key:
byte[] key = "1234567890abcdef1234567890987654".getBytes();
// 加密:
byte[] data = message.getBytes();
byte[] encrypted = encrypt(key, data);
System.out.println("Encrypted(加密内容): " +
Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = null;
System.out.println("Decrypted(解密内容): " + new String(decrypted));
}
// 加密:
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 设置算法/工作模式CBC/填充
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 恢复秘钥对象
SecretKey secretKey = new SecretKeySpec(key, "AES");
// CBC模式需要生成一个16 bytes的initialization vector:
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] iv = random.generateSeed(16);
System.out.println(Arrays.toString(iv));
IvParameterSpec ivp = new IvParameterSpec(iv);
System.out.println(ivp);
// 初始化秘钥:操作模式、秘钥、IV参数
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivp);
System.out.println("-----------");
// 加密
byte[] bu = cipher.doFinal(input);
System.out.println("------" + bu);
// IV不需要保密,把IV和密文一起返回:
return join(iv, bu);
}
// 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 把input分割成IV和密文:
byte[] iv = new byte[16];
byte[] data = new byte[input.length-iv.length];
// 解密:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(key, "AES");
IvParameterSpec ivp = new IvParameterSpec(iv);
// 初始化秘钥:操作模式、秘钥、IV参数
cipher.init(Cipher.DECRYPT_MODE, secretKey,ivp);
// 解密操作
return cipher.doFinal(data);
}
// 合并数组
public static byte[] join(byte[] bs1, byte[] bs2) {
byte[] newbuf = new byte[bs1.length+bs2.length];
System.arraycopy(bs1, 0, newbuf, 0, bs1.length);
System.arraycopy(bs2, 0, newbuf, bs1.length, bs2.length);
return newbuf;
}
}