SM4加密算法

SM4加密算法

复制代码
/**
 * SM4加密工具类
 * SM4算法是一种分组密码算法,分组长度为128位,密钥长度为128位
 */
public class SM4Util {

    static {
        // 加入BouncyCastle支持
        Security.addProvider(new BouncyCastleProvider());
    }

    // 算法名称
    public static final String ALGORITHM_NAME = "SM4";
    // 加密算法/分组加密模式/填充方式
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
    public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";
    // 密钥长度,128位
    public static final int KEY_SIZE = 128;

    /**
     * 生成ECB模式的密钥
     * @return 16位密钥
     * @throws Exception 异常
     */
    public static String generateKey() throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
        kg.init(KEY_SIZE, new SecureRandom());
        return ByteUtils.toHexString(kg.generateKey().getEncoded());
    }

    /**
     * 生成CBC模式的初始化向量
     * @return 16位初始化向量
     */
    public static String generateIV() {
        SecureRandom random = new SecureRandom();
        byte[] iv = new byte[16];
        random.nextBytes(iv);
        return ByteUtils.toHexString(iv);
    }

    /**
     * ECB模式加密
     * @param plainText 明文
     * @param key 密钥(16位十六进制字符串)
     * @return 加密后的Base64字符串
     * @throws Exception 异常
     */
    public static String encryptEcb(String plainText, String key) throws Exception {
        // 将密钥转换为字节数组
        byte[] keyData = ByteUtils.fromHexString(key);
        // 初始化密钥
        Key secretKey = new SecretKeySpec(keyData, ALGORITHM_NAME);

        // 实例化加密器
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        // 加密
        byte[] encryptedData = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        // 返回Base64编码结果
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * ECB模式解密
     * @param cipherText 加密后的Base64字符串
     * @param key 密钥(16位十六进制字符串)
     * @return 解密后的明文
     * @throws Exception 异常
     */
    public static String decryptEcb(String cipherText, String key) throws Exception {
        // 解码Base64
        byte[] encryptedData = Base64.getDecoder().decode(cipherText);
        // 将密钥转换为字节数组
        byte[] keyData = ByteUtils.fromHexString(key);
        // 初始化密钥
        Key secretKey = new SecretKeySpec(keyData, ALGORITHM_NAME);

        // 实例化解密器
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_ECB_PADDING, BouncyCastleProvider.PROVIDER_NAME);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        // 解密
        byte[] decryptedData = cipher.doFinal(encryptedData);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    /**
     * CBC模式加密
     * @param plainText 明文
     * @param key 密钥(16位十六进制字符串)
     * @param iv 初始化向量(16位十六进制字符串)
     * @return 加密后的Base64字符串
     * @throws Exception 异常
     */
    public static String encryptCbc(String plainText, String key, String iv) throws Exception {
        // 将密钥和IV转换为字节数组
        byte[] keyData = ByteUtils.fromHexString(key);
        byte[] ivData = ByteUtils.fromHexString(iv);

        // 初始化密钥和IV
        Key secretKey = new SecretKeySpec(keyData, ALGORITHM_NAME);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);

        // 实例化加密器
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

        // 加密
        byte[] encryptedData = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * CBC模式解密
     * @param cipherText 加密后的Base64字符串
     * @param key 密钥(16位十六进制字符串)
     * @param iv 初始化向量(16位十六进制字符串)
     * @return 解密后的明文
     * @throws Exception 异常
     */
    public static String decryptCbc(String cipherText, String key, String iv) throws Exception {
        // 解码Base64
        byte[] encryptedData = Base64.getDecoder().decode(cipherText);
        // 将密钥和IV转换为字节数组
        byte[] keyData = ByteUtils.fromHexString(key);
        byte[] ivData = ByteUtils.fromHexString(iv);

        // 初始化密钥和IV
        Key secretKey = new SecretKeySpec(keyData, ALGORITHM_NAME);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);

        // 实例化解密器
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_CBC_PADDING, BouncyCastleProvider.PROVIDER_NAME);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);

        // 解密
        byte[] decryptedData = cipher.doFinal(encryptedData);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }
}
相关推荐
曹牧10 分钟前
文档格式:OFD
java
豆角焖肉35 分钟前
Maven进阶与搭建私服
java·maven
大不点wow1 小时前
Java序列化与反序列化:让对象走出JVM
java·开发语言·jvm
阿里嘎多学长1 小时前
2026-07-22 GitHub 热点项目精选
开发语言·程序员·github·代码托管
噢,我明白了1 小时前
Java中日期和字符串的处理
java·开发语言·日期
爱刷碗的苏泓舒1 小时前
C 语言 if-else 与 switch-case 分支语句对比
c语言·开发语言
dkbnull1 小时前
Spring Boot请求处理组件对比详解
java·spring boot
jun_bai1 小时前
Orthanc服务器使用java上传dicom影像文件
java·运维·服务器
-银雾鸢尾-1 小时前
C#中的泛型约束
开发语言·c#
顺风尿一寸1 小时前
记一次 Spring AOP 与定时任务引发的死锁排查
java