Java AES 加密

一、参考

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 因为需要反复加密和解密,速度可能会更慢。

相关推荐
程序员小凯1 小时前
Spring Boot测试框架详解
java·spring boot·后端
你的人类朋友2 小时前
什么是断言?
前端·后端·安全
程序员小凯3 小时前
Spring Boot缓存机制详解
spring boot·后端·缓存
i学长的猫3 小时前
Ruby on Rails 从0 开始入门到进阶到高级 - 10分钟速通版
后端·ruby on rails·ruby
用户21411832636023 小时前
别再为 Claude 付费!Codex + 免费模型 + cc-switch,多场景 AI 编程全搞定
后端
茯苓gao4 小时前
Django网站开发记录(一)配置Mniconda,Python虚拟环境,配置Django
后端·python·django
Cherry Zack4 小时前
Django视图进阶:快捷函数、装饰器与请求响应
后端·python·django
爱读源码的大都督4 小时前
为什么有了HTTP,还需要gPRC?
java·后端·架构
码事漫谈4 小时前
致软件新手的第一个项目指南:阶段、文档与破局之道
后端
间彧4 小时前
Spring Boot条件注解详解与项目实战
后端