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);
    }
}
相关推荐
chools12 分钟前
学习问题日记-4
java
小苏兮14 分钟前
【C++】stack与queue的使用与模拟实现
开发语言·c++
懒人Ethan27 分钟前
解决一个C# 在Framework 4.5反序列化的问题
java·前端·c#
2351640 分钟前
【MySQL】MVCC:从核心原理到幻读解决方案
java·数据库·后端·sql·mysql·缓存
扶苏-su1 小时前
Java---注解
java·注解
高山有多高1 小时前
栈:“后进先出” 的艺术,撑起程序世界的底层骨架
c语言·开发语言·数据结构·c++·算法
蔗理苦1 小时前
2025-10-07 Python不基础 19——私有对象
开发语言·python·私有对象
MX_93591 小时前
SpringBoot项目优先级以及bean的管理
java·spring boot·后端·spring
greentea_20132 小时前
Codeforces Round 65 C. Round Table Knights(71)
c语言·开发语言·算法
小秋学嵌入式-不读研版2 小时前
C61-结构体数组
c语言·开发语言·数据结构·笔记·算法