背景

平时我们的业务偶尔需要对前后端传输的参数进行加密,某些情况下(比如交付给国企单位的项目)要求一定要用国密算法来加密,这里整理了 sm2、sm3、sm4 的加解密方法封装,内部是基于 hutool 的工具再次封装,其实 hutool 内部是基于 bouncycastle 库进行封装的

引入第三方库

在 pom 中引入 hutool、bouncycastle

            <!-- hutool -->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.8.25</version>
            </dependency>

            <!--加密工具包-->
            <dependency>
                <groupId>org.bouncycastle</groupId>
                <artifactId>bcprov-jdk18on</artifactId>
                <version>1.79</version>
            </dependency>

hutool 加密例子介绍

不想看例子的话,可以直接跳到 #最终封装CommonSmCryptogramUtils,复制最终的封装类到你的项目中用

生成密钥的工具方法

生成 SM2 密钥对

生成 SM2 密钥对,用到了 BC 库的方法

    /**
     * 生成sm2密钥对
     */
    @Test
    public void generateSm2KeyPair() {
        SM2 sm2 = new SM2();
        ECPublicKey publicKey = (ECPublicKey) sm2.getPublicKey();
        ECPrivateKey privateKey = (ECPrivateKey) sm2.getPrivateKey();

        byte[] publicKeyBytes = publicKey.getQ().getEncoded(false);
        String publicKeyHex = HexUtil.encodeHexStr(publicKeyBytes);

        String privateKeyHex = privateKey.getD().toString(16);
        // BigInteger转成16进制时,不一定长度为64,如果私钥长度小于64,则在前方补0
        StringBuilder privateKey64 = new StringBuilder(privateKeyHex);
        while (privateKey64.length() < 64) {
            privateKey64.insert(0, "0");
        }
        privateKeyHex = privateKey64.toString();

        System.out.println("sm2PublicKey: " + publicKeyHex);
        System.out.println("sm2PrivateKey: " + privateKeyHex);
    }

生成 SM4 密钥和 IV 值

SM4 密钥和 iv 值,其实只是普通的 16 字节的数据,随机生成即可

    /**
     * 生成sm4秘钥
     */
    @Test
    public void generateSm4Key() {
        System.out.println("sm4Key: " + generateRandomHexStr(16));
    }

    /**
     * 生成sm4的iv
     */
    @Test
    public static String generateSm4Iv() {
        System.out.println("sm4Iv: " + generateRandomHexStr(16));
    }

    /**
     * 随机生成指定字节数的十六进制编码
     * @param byteCount 字节数
     * @return 十六进制编码
     */
    public String generateRandomHexStr(int byteCount) {
        SecureRandom random= new SecureRandom();
        byte[] bytes = new byte[byteCount];
        random.nextBytes(bytes);
        return HexUtil.encodeHexStr(bytes);
    }

SM2

加解密

    @Test
    public void testHutoolSm2() {
        String text = "admin123";
        {
            // 构造函数里什么都不传,则是使用它内部随机生成的密钥对
            System.out.println("-------------- 构造函数里什么都不传,则是使用它内部随机生成的密钥对 ---------------");
            SM2 sm2 = new SM2();
            String encrypt = HexUtil.encodeHexStr(sm2.encrypt(text.getBytes()));
            System.out.println("1)密文16进制字符串:" + encrypt);
            System.out.println("1)解密后明文字符串:" + new String(sm2.decrypt(HexUtil.decodeHex(encrypt))));
            System.out.println();
        }

        {
            // 使用指定的公私钥(密钥对使用上面说的生成sm2密钥对的方法来生成)
            String publicKey = "04349bdbf50cda0abf46692ed5eecca93ee4efed4478f958b1bd793bae501fe6205d8e9234781113715feb05ee6c0e12eb280409f3c4ddcc769283be66adb46921";
            String privateKey = "67eb8864b70582a60b2f1250424d4fbedfb8ec0a7bf5523095df14864271d013";

            // 公私钥都传进去,可以加密,也可以解密
            {
                System.out.println("-------------- 公私钥都传进去,可以加密,也可以解密 ---------------");
                SM2 sm2 = new SM2(privateKey, publicKey);
                String encrypt = HexUtil.encodeHexStr(sm2.encrypt(text.getBytes()));
                System.out.println("密文16进制字符串:" + encrypt);
                System.out.println("解密后明文字符串:" + new String(sm2.decrypt(HexUtil.decodeHex(encrypt))));
                System.out.println();

            }

            // 只传公钥,只能加密
            {
                System.out.println("-------------- 只传公钥,只能加密 ---------------");
                SM2 sm2 = new SM2(null, publicKey);
                String encrypt = HexUtil.encodeHexStr(sm2.encrypt(text.getBytes()));
                System.out.println("密文16进制字符串:" + encrypt);
                System.out.println();
            }

            // 只传私钥,只能解密
            {
                System.out.println("-------------- 只传私钥,只能解密 ---------------");
                SM2 sm2 = new SM2(privateKey, null);
                String encrypt = "04787e2b3b059c5b606ff4cc4b2a6cf9bcb6758808e81f2ebc612586ee7907db5c9089010e12df9cc99cc1ffa3ae99ae06bde8102182e557374d27b1af9ee7493da5bb023a636f64ded0e9744d212069b3a2bf34e496b57f6761b1c3c76f3d127deddec674805de620";
                System.out.println("密文16进制字符串:" + encrypt);
                System.out.println("解密后明文字符串:" + new String(sm2.decrypt(HexUtil.decodeHex(encrypt))));
                System.out.println();
            }
        }
    }

加签验签

    @Test
    public void testHutoolSm2Sign() {
        String text = "admin123";

        {
            // 使用指定的公私钥
            String publicKey = "04349bdbf50cda0abf46692ed5eecca93ee4efed4478f958b1bd793bae501fe6205d8e9234781113715feb05ee6c0e12eb280409f3c4ddcc769283be66adb46921";
            String privateKey = "67eb8864b70582a60b2f1250424d4fbedfb8ec0a7bf5523095df14864271d013";

            // 使用私钥加签,公钥验签
            {
                System.out.println("-------------- 使用私钥加签,公钥验签 ---------------");
                // 也可以单独传入私钥只做加签,或者单独传入公钥只做验签
                SM2 sm2 = new SM2(privateKey, publicKey);
                String signHex = HexUtil.encodeHexStr(sm2.sign(text.getBytes()));
                System.out.println("签名16进制字符串:" + signHex);
                System.out.println("验签结果:" + sm2.verify(text.getBytes(), HexUtil.decodeHex(signHex)));
            }
        }
    }

SM3

SM3 生成摘要

    @Test
    public void testHutoolSm3() {
        String text = "admin123";
        // 不加salt
        {
            SM3 sm3 = new SM3();
            System.out.println("不加salt: " + sm3.digestHex(text.getBytes()));
        }

        // 加salt
        {
            String salt = "this is salt";
            SM3 sm3 = new SM3(salt.getBytes());
            System.out.println("加salt: " + sm3.digestHex(text.getBytes()));
        }
    }

SM4

SM4 可以设置模式(CBC、ECB 等等)、填充方式(PKCS5Padding、ZeroPadding 等等)

下面以 CBC/PKCS5Padding 为例子

    @Test
    public void testHutoolSm4() {
        // 密钥和iv使用前面说的生成方式生成
        String key = "c88d7433938f213105f546e52eb86f3a";
        String iv = "885fa5d11189460386aec69233ccb5f3";

        String text = "admin123";

        SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(key), HexUtil.decodeHex(iv));
        String encodeHexStr = HexUtil.encodeHexStr(sm4.encrypt(text.getBytes()));
        System.out.println("密文: " + encodeHexStr);
        System.out.println("明文: " + new String(sm4.decrypt(HexUtil.decodeHex(encodeHexStr))));
    }

最终封装CommonSmCryptogramUtils

定义密钥对类

package com.kk.utils;

import lombok.Data;

@Data
public class Keypair {

    protected String privateKey;

    protected String publicKey;

    public Keypair() {
    }

    public Keypair(String privateKey, String publicKey) {
        this.privateKey = privateKey;
        this.publicKey = publicKey;
    }

    public String toString() {
        return "Keypair{\n privateKey: " + this.privateKey + "\n publicKey: " + this.publicKey + "\n}";
    }

}

封装工具类

下面 CommonSmCryptogramUtil 类中的 SM2_PRIVATE_KEY、SM2_PUBLIC_KEY、SM4_KEY、SM4_IV 这几个默认密钥要按照注释里写的方法来生成哦

package com.kk.utils;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.digest.SM3;
import cn.hutool.crypto.symmetric.SM4;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.signers.DSAEncoding;
import org.bouncycastle.crypto.signers.StandardDSAEncoding;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;

import java.io.InputStream;
import java.security.SecureRandom;

public class CommonSmCryptogramUtil {

    // 可以调用generateSm2KeyPair()方法来生成
    public static final String SM2_PRIVATE_KEY = "sm2私钥";
    public static final String SM2_PUBLIC_KEY = "sm2公钥";

    // 可以调用generateSm4Key()生成
    public static final String SM4_KEY = "sm4密钥";
    // 可以调用generateSm4Iv()生成
    public static final String SM4_IV = "sm4 iv";

    public static SecureRandom RANDOM = new SecureRandom();

    /**
     * 生成sm2密钥对
     * 公钥:keypair.getPublicKey()
     * 私钥:keypair.getPrivateKey()
     *
     * @return 密钥对
     */
    public static Keypair generateSm2KeyPair() {
        SM2 sm2 = new SM2();
        ECPublicKey publicKey = (ECPublicKey) sm2.getPublicKey();
        ECPrivateKey privateKey = (ECPrivateKey) sm2.getPrivateKey();

        byte[] publicKeyBytes = publicKey.getQ().getEncoded(false);
        String publicKeyHex = HexUtil.encodeHexStr(publicKeyBytes);

        String privateKeyHex = privateKey.getD().toString(16);
        // BigInteger转成16进制时,不一定长度为64,如果私钥长度小于64,则在前方补0
        StringBuilder privateKey64 = new StringBuilder(privateKeyHex);
        while (privateKey64.length() < 64) {
            privateKey64.insert(0, "0");
        }
        privateKeyHex = privateKey64.toString();

        return new Keypair(privateKeyHex, publicKeyHex);
    }

    /**
     * 生成sm4秘钥
     *
     * @return 秘钥十六进制编码
     */
    public static String generateSm4Key() {
        return generateRandomHexStr(16);
    }

    /**
     * 生成sm4的iv
     *
     * @return iv十六进制编码
     */
    public static String generateSm4Iv() {
        return generateRandomHexStr(16);
    }

    /**
     * 随机生成指定字节数的十六进制编码
     *
     * @param byteCount 字节数
     * @return 十六进制编码
     */
    public static String generateRandomHexStr(int byteCount) {
        byte[] bytes = new byte[byteCount];
        RANDOM.nextBytes(bytes);
        return HexUtil.encodeHexStr(bytes);
    }

    /**
     * sm2默认公钥加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm2Encrypt(String str) {
        return sm2Encrypt(str, SM2_PUBLIC_KEY);
    }

    /**
     * sm2默认公钥加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm2EncryptFromBytes(byte[] data) {
        return sm2EncryptFromBytes(data, SM2_PUBLIC_KEY);
    }

    /**
     * sm2公钥加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm2Encrypt(String str, String publicKey) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return sm2EncryptFromBytes(str.getBytes(), publicKey);
    }

    /**
     * sm2公钥加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm2EncryptFromBytes(byte[] data, String publicKey) {
        return sm2EncryptFromBytes(data, publicKey, SM2Engine.Mode.C1C3C2, new SM3Digest());
    }

    /**
     * sm2公钥加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm2EncryptFromBytes(byte[] data, String publicKey, SM2Engine.Mode mode, Digest digest) {
        if (data == null || data.length == 0) {
            return data == null ? null : "";
        }
        SM2 sm2 = new SM2(null, publicKey);
        sm2.setMode(mode);
        sm2.setDigest(digest);
        try {
            return HexUtil.encodeHexStr(sm2.encrypt(data));
        } catch (Exception e) {
            throw new RuntimeException("SM2加密失败", e);
        }
    }

    /**
     * sm2用默认私钥解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static String sm2Decrypt(String hexStr) {
        return sm2Decrypt(hexStr, SM2_PRIVATE_KEY);
    }

    /**
     * sm2用默认私钥解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static byte[] sm2DecryptToBytes(String hexStr) {
        return sm2DecryptToBytes(hexStr, SM2_PRIVATE_KEY);
    }

    /**
     * sm2私钥解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static String sm2Decrypt(String hexStr, String privateKey) {
        if (hexStr == null || hexStr.isEmpty()) {
            return null;
        }
        return new String(sm2DecryptToBytes(hexStr, privateKey));
    }

    /**
     * sm2私钥解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static byte[] sm2DecryptToBytes(String hexStr, String privateKey) {
        return sm2DecryptToBytes(hexStr, privateKey, SM2Engine.Mode.C1C3C2, new SM3Digest());
    }

    /**
     * sm2私钥解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static byte[] sm2DecryptToBytes(String hexStr, String privateKey, SM2Engine.Mode mode, Digest digest) {
        if (hexStr == null || hexStr.isEmpty()) {
            return null;
        }
        // 前端使用的是sm-crypto库,秘文不会有04开头,得加上
        if (!hexStr.startsWith("04")) {
            hexStr = "04" + hexStr;
        }
        SM2 sm2 = new SM2(privateKey, null);
        sm2.setMode(mode);
        sm2.setDigest(digest);
        try {
            return sm2.decrypt(HexUtil.decodeHex(hexStr));
        } catch (Exception e) {
            throw new RuntimeException("SM2解密失败", e);
        }
    }

    /**
     * sm4 cbc 用默认秘钥加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm4CbcEncrypt(String str) {
        return sm4CbcEncrypt(str, SM4_KEY, SM4_IV);
    }

    /**
     * sm4 cbc 用默认秘钥加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm4CbcEncryptFromBytes(byte[] data) {
        return sm4CbcEncryptFromBytes(data, SM4_KEY, SM4_IV);
    }

    /**
     * sm4 cbc 加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm4CbcEncrypt(String str, String keyHex, String ivHex) {
        if (str == null) {
            return null;
        }
        return sm4CbcEncryptFromBytes(str.getBytes(), keyHex, ivHex);
    }

    /**
     * sm4 cbc 加密
     *
     * @return 秘文十六进制编码
     */
    public static String sm4CbcEncryptFromBytes(byte[] data, String keyHex, String ivHex) {
        return sm4EncryptFromBytes(data, keyHex, ivHex, Mode.CBC.name(), Padding.PKCS5Padding.name());
    }

    /**
     * sm4 cbc 加密
     *
     * @param mode    看{@link Mode}
     * @param padding 看{@link Padding}
     * @return 秘文十六进制编码
     */
    public static String sm4EncryptFromBytes(byte[] data, String keyHex, String ivHex, String mode, String padding) {
        if (data == null) {
            return null;
        }
        SM4 sm4 = new SM4(mode, padding, HexUtil.decodeHex(keyHex), StrUtil.isBlank(ivHex) ? null : HexUtil.decodeHex(ivHex));
        try {
            return HexUtil.encodeHexStr(sm4.encrypt(data));
        } catch (Exception e) {
            throw new RuntimeException("SM4 CBC加密失败", e);
        }
    }

    /**
     * sm4 cbc 用默认秘钥解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static String sm4CbcDecrypt(String hexStr) {
        return sm4CbcDecrypt(hexStr, SM4_KEY, SM4_IV);
    }

    /**
     * sm4 cbc 用默认秘钥解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static byte[] sm4CbcDecryptToBytes(String hexStr) {
        return sm4CbcDecryptToBytes(hexStr, SM4_KEY, SM4_IV);
    }

    /**
     * sm4 cbc 解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static String sm4CbcDecrypt(String hexStr, String keyHex, String ivHex) {
        if (hexStr == null || hexStr.isEmpty()) {
            return null;
        }
        return new String(sm4CbcDecryptToBytes(hexStr, keyHex, ivHex));
    }

    /**
     * sm4 cbc 解密
     *
     * @param hexStr 秘文十六进制编码
     * @return 明文
     */
    public static byte[] sm4CbcDecryptToBytes(String hexStr, String keyHex, String ivHex) {
        return sm4DecryptToBytes(hexStr, keyHex, ivHex, Mode.CBC.name(), Padding.PKCS5Padding.name());
    }

    /**
     * sm4 cbc 解密
     *
     * @param hexStr  秘文十六进制编码
     * @param mode    看{@link Mode}
     * @param padding 看{@link Padding}
     * @return 明文
     */
    public static byte[] sm4DecryptToBytes(String hexStr, String keyHex, String ivHex, String mode, String padding) {
        if (hexStr == null || hexStr.isEmpty()) {
            return null;
        }
        SM4 sm4 = new SM4(mode, padding, HexUtil.decodeHex(keyHex), StrUtil.isBlank(ivHex) ? null : HexUtil.decodeHex(ivHex));
        try {
            return sm4.decrypt(HexUtil.decodeHex(hexStr));
        } catch (Exception e) {
            throw new RuntimeException("SM4 CBC解密失败", e);
        }
    }

    /**
     * sm2用默认私钥签名
     *
     * @return 签名十六进制编码
     */
    public static String sm2Signature(String str) {
        return sm2Signature(str, SM2_PRIVATE_KEY);
    }

    /**
     * sm2私钥签名
     *
     * @return 签名十六进制编码
     */
    public static String sm2Signature(String str, String privateKey) {
        return sm2Signature(str, privateKey, StandardDSAEncoding.INSTANCE, new SM3Digest());
    }

    /**
     * sm2私钥签名
     *
     * @return 签名十六进制编码
     */
    public static String sm2Signature(String str, String privateKey, DSAEncoding encoding, Digest digest) {
        if (str == null) {
            return null;
        }
        SM2 sm2 = new SM2(privateKey, null);
        sm2.setEncoding(encoding);
        sm2.setDigest(digest);
        try {
            return HexUtil.encodeHexStr(sm2.sign(str.getBytes()));
        } catch (Exception e) {
            throw new RuntimeException("SM2签名失败", e);
        }
    }

    /**
     * sm2用默认公钥验证签名结果
     */
    public static boolean sm2VerifySignature(String originalStr, String signHexStr) {
        return sm2VerifySignature(originalStr, signHexStr, SM2_PUBLIC_KEY);
    }

    /**
     * sm2验证签名结果
     */
    public static boolean sm2VerifySignature(String originalStr, String signHexStr, String publicKey) {
        return sm2VerifySignature(originalStr, signHexStr, publicKey, StandardDSAEncoding.INSTANCE, new SM3Digest());
    }

    /**
     * sm2验证签名结果
     */
    public static boolean sm2VerifySignature(String originalStr, String signHexStr, String publicKey, DSAEncoding encoding, Digest digest) {
        if (originalStr == null || signHexStr == null || signHexStr.isEmpty()) {
            return false;
        }
        SM2 sm2 = new SM2(null, publicKey);
        sm2.setEncoding(encoding);
        sm2.setDigest(digest);
        try {
            return sm2.verify(originalStr.getBytes(), HexUtil.decodeHex(signHexStr));
        } catch (Exception e) {
            throw new RuntimeException("SM2验证签名失败", e);
        }
    }

    /**
     * sm3取哈希
     *
     * @return 摘要十六进制编码
     */
    public static String sm3HashValue(String dataStr) {
        if (dataStr == null) {
            return null;
        }
        SM3 sm3 = new SM3();
        try {
            return sm3.digestHex(dataStr.getBytes());
        } catch (Exception e) {
            throw new RuntimeException("SM3计算摘要失败", e);
        }
    }

    /**
     * sm3取哈希
     *
     * @return 摘要十六进制编码
     */
    public static String sm3HashValue(byte[] data) {
        if (data == null) {
            return null;
        }
        SM3 sm3 = new SM3();
        try {
            return sm3.digestHex(data);
        } catch (Exception e) {
            throw new RuntimeException("SM3计算摘要失败", e);
        }
    }

    /**
     * sm3取哈希
     *
     * @param dataStr 字符串数据
     * @param salt    添加的盐值
     * @return 摘要十六进制编码
     */
    public static String sm3HashValue(String dataStr, byte[] salt) {
        if (dataStr == null) {
            return null;
        }
        SM3 sm3 = new SM3(salt);
        try {
            return sm3.digestHex(dataStr.getBytes());
        } catch (Exception e) {
            throw new RuntimeException("SM3计算摘要失败", e);
        }
    }

    /**
     * sm3取哈希
     *
     * @param salt 添加的盐值
     * @return 摘要十六进制编码
     */
    public static String sm3HashValue(InputStream inputStream, byte[] salt) {
        SM3 sm3 = new SM3(salt);
        try {
            return sm3.digestHex(inputStream);
        } catch (Exception e) {
            throw new RuntimeException("SM3计算摘要失败", e);
        }
    }

}

工具类使用例子

生成 SM2 密钥对

    @Test
    public void testGenSm2Keypair() {
        Keypair keypair = CommonSmCryptogramUtil.generateSm2KeyPair();
        System.out.println("sm2PublicKey: " + keypair.getPublicKey());
        System.out.println("sm2PrivateKey: " + keypair.getPrivateKey());
    }

生成 SM4 密钥和 IV

    @Test
    public void testGenSm4Key() {
        System.out.println("sm4Key: " + CommonSmCryptogramUtil.generateSm4Key());
        System.out.println("sm4Iv: " + CommonSmCryptogramUtil.generateSm4Iv());
    }

测试 SM2 加解密、加签验签

    @Test
    public void testSm2() {
        String val = "admin";
        {
            // 默认使用 c1c3c2模式,sm3做摘要
            System.out.println("---------------- c1c3c2+sm3 加解密 -------------------");
            String sm2EncryptVal = CommonSmCryptogramUtil.sm2Encrypt(val);
            System.out.println("(c1c3c2+sm3)sm2加密:" + sm2EncryptVal);
            System.out.println("(c1c3c2+sm3)sm2解密:" + CommonSmCryptogramUtil.sm2Decrypt(sm2EncryptVal));
            System.out.println();

            // 默认使用 sm3做摘要,ASN1编码方式
            System.out.println("---------------- ASN1编码 加签验签 -------------------");
            String sm2SignatureVal = CommonSmCryptogramUtil.sm2Signature(val);
            System.out.println("(ASN1)sm2签名:" + sm2SignatureVal);
            System.out.println("(ASN1)sm2验证签名:" + CommonSmCryptogramUtil.sm2VerifySignature(val, sm2SignatureVal));
            System.out.println();
        }

        {
            // 使用c1c2c3模式
            System.out.println("---------------- c1c2c3+sm3 加解密 -------------------");
            String sm2EncryptVal = CommonSmCryptogramUtil.sm2EncryptFromBytes(val.getBytes(), CommonSmCryptogramUtil.SM2_PUBLIC_KEY, SM2Engine.Mode.C1C2C3, new SM3Digest());
            System.out.println("(c1c2c3+sm3)sm2加密:" + sm2EncryptVal);
            System.out.println("(c1c2c3+sm3)sm2解密:" + new String(CommonSmCryptogramUtil.sm2DecryptToBytes(sm2EncryptVal, CommonSmCryptogramUtil.SM2_PRIVATE_KEY, SM2Engine.Mode.C1C2C3, new SM3Digest())));
            System.out.println();

            // 使用sm3做摘要,Plain编码方式
            System.out.println("---------------- Plain编码 加签验签 -------------------");
            String sm2SignatureVal = CommonSmCryptogramUtil.sm2Signature(val, CommonSmCryptogramUtil.SM2_PRIVATE_KEY, PlainDSAEncoding.INSTANCE, new SM3Digest());
            System.out.println("(Plain)sm2签名:" + sm2SignatureVal);
            System.out.println("(Plain)sm2验证签名:" + CommonSmCryptogramUtil.sm2VerifySignature(val, sm2SignatureVal, CommonSmCryptogramUtil.SM2_PUBLIC_KEY, PlainDSAEncoding.INSTANCE, new SM3Digest()));
        }
    }

测试 SM3 生成摘要

    @Test
    public void testSm3() {
        String val = "admin";
        System.out.println("sm3哈希:" + CommonSmCryptogramUtil.sm3HashValue(val));
        System.out.println("sm3哈希(加salt): + " + CommonSmCryptogramUtil.sm3HashValue(val, "this is salt".getBytes()));
    }

测试 SM4 加解密

    @Test
    public void testSm4() {
        String val = "admin";

        {
            // 默认是 CBC/PKCS5Padding
            System.out.println("------------------- CBC/PKCS5Padding -----------------");
            String sm4EncryptVal = CommonSmCryptogramUtil.sm4CbcEncrypt(val);
            System.out.println("sm4加密:" + sm4EncryptVal);
            System.out.println("sm4解密:" + CommonSmCryptogramUtil.sm4CbcDecrypt(sm4EncryptVal));
            System.out.println();
        }
        {
            System.out.println("------------------- CBC/PKCS7Padding -----------------");
            String sm4EncryptVal = CommonSmCryptogramUtil.sm4EncryptFromBytes(val.getBytes(), CommonSmCryptogramUtil.SM4_KEY, CommonSmCryptogramUtil.SM4_IV, Mode.CBC.name(), "PKCS7Padding");
            System.out.println("sm4加密:" + sm4EncryptVal);
            System.out.println("sm4解密:" + new String(CommonSmCryptogramUtil.sm4DecryptToBytes(sm4EncryptVal, CommonSmCryptogramUtil.SM4_KEY, CommonSmCryptogramUtil.SM4_IV, Mode.CBC.name(), "PKCS7Padding")));
            System.out.println();
        }
        {
            System.out.println("------------------- ECB/PKCS7Padding (注意:ECB模式不需要iv) -----------------");
            String sm4EncryptVal = CommonSmCryptogramUtil.sm4EncryptFromBytes(val.getBytes(), CommonSmCryptogramUtil.SM4_KEY, null, Mode.ECB.name(), "PKCS7Padding");
            System.out.println("sm4加密:" + sm4EncryptVal);
            System.out.println("sm4解密:" + new String(CommonSmCryptogramUtil.sm4DecryptToBytes(sm4EncryptVal, CommonSmCryptogramUtil.SM4_KEY, null, Mode.ECB.name(), "PKCS7Padding")));
            System.out.println();
        }
    }