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);
    }
}
相关推荐
毕设源码-邱学长1 小时前
【开题答辩全过程】以 基于Java的学校住宿管理系统的设计与实现为例,包含答辩的问题和答案
java·开发语言
rookieﻬ°2 小时前
PHP框架漏洞
开发语言·php
炸膛坦客2 小时前
单片机/C/C++八股:(二十)指针常量和常量指针
c语言·开发语言·c++
兑生3 小时前
【灵神题单·贪心】1481. 不同整数的最少数目 | 频率排序贪心 | Java
java·开发语言
daidaidaiyu3 小时前
一文学习 Spring 声明式事务源码全流程总结
java·spring
炸膛坦客4 小时前
单片机/C/C++八股:(十九)栈和堆的区别?
c语言·开发语言·c++
零雲4 小时前
java面试:了解抽象类与接口么?讲一讲它们的区别
java·开发语言·面试
Jay_Franklin4 小时前
Quarto与Python集成使用
开发语言·python·markdown
2401_831824965 小时前
代码性能剖析工具
开发语言·c++·算法
是wzoi的一名用户啊~5 小时前
【C++小游戏】2048
开发语言·c++