一、参考
Java 实现 AES 加密和解密完整示例_java实现aes的五种加密模式_=蜗牛=的博客-CSDN博客
二、ECB
2.1 定义
这种模式是将整个明文分成若干段相同的小段,然后对每一小段进行加密。加密时,使用一个密钥,将明文中的每个字符与密钥中对应位置的字符进行异或运算,得到密文。
2.2 代码
2.2.1 ECB工具类
java
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class ECB {
/** 加密模式之 ECB,算法/模式/补码方式 */
public static final String AES_ECB = "AES/ECB/PKCS5Padding";
/***
* <h2>空校验</h2>
* @param str 需要判断的值
*/
public static boolean isEmpty(Object str) {
return null == str || "".equals(str);
}
/***
* <h2>String 转 byte</h2>
* @param str 需要转换的字符串
*/
public static byte[] getBytes(String str){
if (isEmpty(str)) {
return null;
}
try {
return str.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/***
* <h2>获取一个 AES 密钥规范</h2>
*/
public static SecretKeySpec getSecretKeySpec(String key){
SecretKeySpec secretKeySpec = new SecretKeySpec(getBytes(key), "AES");
return secretKeySpec;
}
/**
* <h2>加密 - 模式 ECB</h2>
* @param text 需要加密的文本内容
* @param key 加密的密钥 key
* */
public static String encrypt(String text, String key){
if (isEmpty(text) || isEmpty(key)) {
return null;
}
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_ECB);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
// 加密字节数组
byte[] encryptedBytes = cipher.doFinal(getBytes(text));
// 将密文转换为 Base64 编码字符串
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* <h2>解密 - 模式 ECB</h2>
* @param text 需要解密的文本内容
* @param key 解密的密钥 key
* */
public static String decrypt(String text, String key){
if (isEmpty(text) || isEmpty(key)) {
return null;
}
// 将密文转换为16字节的字节数组
byte[] textBytes = Base64.getDecoder().decode(text);
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_ECB);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// 解密字节数组
byte[] decryptedBytes = cipher.doFinal(textBytes);
// 将明文转换为字符串
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2.2.2 测试
java
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws Exception {
String text = "嗨,您好!";
String key = "woniucsdnvip8888"; // 16字节的密钥
String encryptTextECB = ECB.encrypt(text, key);
System.out.println("EBC 加密后内容:" + encryptTextECB);
System.out.println("EBC 解密后内容:" + ECB.decrypt(encryptTextECB, key));
System.out.println();
}
}
三、CBC
3.1 定义
这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。加密时,使用一个密钥和一个初始化向量(IV),初始化向量是一个16字节的向量,包含了加密算法所需的所有信息。
3.2 代码
3.2.1 CBC工具类
java
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CBC {
/** 加密模式之 CBC,算法/模式/补码方式 */
private static final String AES_CBC = "AES/CBC/PKCS5Padding";
/** AES 中的 IV 必须是 16 字节(128位)长 */
private static final Integer IV_LENGTH = 16;
/***
* <h2>空校验</h2>
* @param str 需要判断的值
*/
public static boolean isEmpty(Object str) {
return null == str || "".equals(str);
}
/***
* <h2>String 转 byte</h2>
* @param str 需要转换的字符串
*/
public static byte[] getBytes(String str){
if (isEmpty(str)) {
return null;
}
try {
return str.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/***
* <h2>获取一个 AES 密钥规范</h2>
*/
public static SecretKeySpec getSecretKeySpec(String key){
SecretKeySpec secretKeySpec = new SecretKeySpec(getBytes(key), "AES");
return secretKeySpec;
}
/**
* <h2>加密 - 自定义加密模式</h2>
* @param text 需要加密的文本内容
* @param key 加密的密钥 key
* */
public static String encrypt(String text, String key,String iv){
if (isEmpty(text) || isEmpty(key) || isEmpty(iv)) {
return null;
}
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_CBC);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(getBytes(iv)));
// 加密字节数组
byte[] encryptedBytes = cipher.doFinal(getBytes(text));
// 将密文转换为 Base64 编码字符串
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* <h2>解密 - 自定义加密模式</h2>
* @param text 需要解密的文本内容
* @param key 解密的密钥 key
* */
public static String decrypt(String text, String key,String iv){
if (isEmpty(text) || isEmpty(key) || isEmpty(iv)) {
return null;
}
// 将密文转换为16字节的字节数组
byte[] textBytes = Base64.getDecoder().decode(text);
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_CBC);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(getBytes(iv)));
// 解密字节数组
byte[] decryptedBytes = cipher.doFinal(textBytes);
// 将明文转换为字符串
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
3.2.2 测试
java
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws Exception {
String text = "嗨,您好!";
String key = "woniucsdnvip8888"; // 16字节的密钥
String iv = key ;
String res = CBC.encrypt(text, key,iv);
System.out.println("CBC 加密后内容:" + res);
System.out.println("CBC 解密后内容:" + CBC.decrypt(res, key,iv));
System.out.println();
}
}
四、CFB
4.1 定义
这种模式是一种较为复杂的加密模式,它结合了CBC和CTR两种模式的优点。在CFB模式中,加密过程中使用一个密钥和一个随机生成的初始化向量(IV),然后对明文进行加密。在加密完成后,通过对明文进行非对称加密来生成密文的向量。随后,通过对密文进行反向操作,将密文的向量与明文的向量进行异或运算,得到解密所需的密钥。
4.2 代码
4.2.1 CFB工具类
java
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CFB {
/** 加密模式之 CBC,算法/模式/补码方式 */
private static final String AES_CBC = "AES/CFB/PKCS5Padding";
/** AES 中的 IV 必须是 16 字节(128位)长 */
private static final Integer IV_LENGTH = 16;
/***
* <h2>空校验</h2>
* @param str 需要判断的值
*/
public static boolean isEmpty(Object str) {
return null == str || "".equals(str);
}
/***
* <h2>String 转 byte</h2>
* @param str 需要转换的字符串
*/
public static byte[] getBytes(String str){
if (isEmpty(str)) {
return null;
}
try {
return str.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/***
* <h2>获取一个 AES 密钥规范</h2>
*/
public static SecretKeySpec getSecretKeySpec(String key){
SecretKeySpec secretKeySpec = new SecretKeySpec(getBytes(key), "AES");
return secretKeySpec;
}
/**
* <h2>加密 - 自定义加密模式</h2>
* @param text 需要加密的文本内容
* @param key 加密的密钥 key
* */
public static String encrypt(String text, String key,String iv){
if (isEmpty(text) || isEmpty(key) || isEmpty(iv)) {
return null;
}
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_CBC);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(getBytes(iv)));
// 加密字节数组
byte[] encryptedBytes = cipher.doFinal(getBytes(text));
// 将密文转换为 Base64 编码字符串
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* <h2>解密 - 自定义加密模式</h2>
* @param text 需要解密的文本内容
* @param key 解密的密钥 key
* */
public static String decrypt(String text, String key,String iv){
if (isEmpty(text) || isEmpty(key) || isEmpty(iv)) {
return null;
}
// 将密文转换为16字节的字节数组
byte[] textBytes = Base64.getDecoder().decode(text);
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_CBC);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(getBytes(iv)));
// 解密字节数组
byte[] decryptedBytes = cipher.doFinal(textBytes);
// 将明文转换为字符串
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
4.2.2 测试
java
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws Exception {
String text = "嗨,您好!";
String key = "woniucsdnvip8888"; // 16字节的密钥
String iv = key ;
String res = CFB.encrypt(text, key,iv);
System.out.println("CFB 加密后内容:" + res);
System.out.println("CFB 解密后内容:" + CFB.decrypt(res, key,iv));
System.out.println();
}
}
五、总结
ECB、CBC、CFB等模式都是对称加密算法,加密和解密使用相同的密钥。在使用这些算法时,需要注意保护密钥的安全,避免被恶意获取。
总的来说,选择 AES 的算法模式需要根据加密需要的安全性和速度来进行选择,通常推荐使用CBC 或 CFB 模式,而不是 ECB 模式
5.1 安全性
ECB 不够安全,只适合于短数据的加密,而 CBC 和 CFB 相较于 ECB 更加安全,因为前一个密文块会影响当前明文块,使攻击者难以预测密文的结构。
5.2 速度
ECB 是最简单的加密方式,速度最快,但由于安全性差不建议使用,CBC 因为每个明文块都要与前一个密文块进行异或操作,比 ECB 要慢一些,CFB 因为需要反复加密和解密,速度可能会更慢。