SM2国密算法

927 阅读2分钟

基础概念

SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。

SM2算法是在国际标准的ECC椭圆曲线密码理论基础上进行自主研发设计,具备ECC算法的性能特点并实现优化改进。

依赖


<dependencies>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.68</version>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.6.5</version>
    </dependency>
</dependencies>

生成公私钥工具类


 public static Map<String, String> generateSmKeyBase64() throws Exception {
    Map<String, String> map = new HashMap<>(2);
    // 生成公私钥对象
    SecureRandom secureRandom = new SecureRandom();
    ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
    // 获取一个椭圆曲线类型的秘钥对生成器
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
    // 使用SM2的算法区域初始化秘钥生成器
    keyPairGenerator.initialize(sm2Spec, secureRandom);
    // 获取秘钥对
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    // 获取公钥
    PublicKey keyPairPublic = keyPair.getPublic();
    byte[] encodedPublicKey = keyPairPublic.getEncoded();
    byte[] bytePublicKey = Base64.getEncoder().encode(encodedPublicKey);
    String publicKey = new String(bytePublicKey, StandardCharsets.UTF_8);
    map.put("publicKey", publicKey);
    // 获取私钥
    PrivateKey keyPairPrivate = keyPair.getPrivate();
    byte[] encodedPrivateKey = keyPairPrivate.getEncoded();
    byte[] bytePrivateKey = Base64.getEncoder().encode(encodedPrivateKey);
    String privateKey = new String(bytePrivateKey, StandardCharsets.UTF_8);
    map.put("privateKey", privateKey);
    return map;
}

加解密工具类



/**
 * @author 苦瓜不苦
 * @date 2022/12/13 15:29
 **/
public class SM2Util {

    private static BCECPublicKey publicKey;
    private static BCECPrivateKey privateKey;

    private final static String PRIVATE_KEY = "xxxxx";

    private final static String PUBLIC_KEY = "xxxxx";


    static {
        try {
            publicKey = (BCECPublicKey) SM2Util.createPublicKey(PUBLIC_KEY);
            privateKey = (BCECPrivateKey) SM2Util.createPrivateKey(PRIVATE_KEY);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 将Base64转码的公钥串,转换为公钥对象
     *
     * @param publicKey Base64公钥串
     * @return
     * @throws Exception
     */
    public static PublicKey createPublicKey(String publicKey) throws Exception {
        // 解码Base64
        byte[] decode = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(decode);
        KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
        return keyFactory.generatePublic(publicKeySpec);
    }

    /**
     * 将Base64转码的私钥串,转换为私钥对象
     *
     * @param privateKey Base64私钥串
     * @return
     * @throws Exception
     */
    public static PrivateKey createPrivateKey(String privateKey) throws Exception {
        // 解码Base64
        byte[] decode = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode);
        KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
        return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
    }

    /**
     * SM2数据加密
     *
     * @param text 未加密数据
     * @return SM2加密后的字符串
     */
    public static String encrypt(String text) {
        try {
            if (Objects.isNull(text)) {
                return null;
            }
            ECParameterSpec ecParameterSpec = publicKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
            ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
            // 加密
            byte[] dataBytes = text.getBytes(StandardCharsets.UTF_8);
            byte[] encryptBytes = sm2Engine.processBlock(dataBytes, 0, dataBytes.length);
            // Base64编码
            byte[] encryptBytesBase64 = Base64.getEncoder().encode(encryptBytes);
            return new String(encryptBytesBase64, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * SM2数据解密
     *
     * @param text 加密数据
     * @return SM2解密后的字符串
     */
    public static String decrypt(String text) {
        try {
            if (Objects.isNull(text)) {
                return null;
            }
            ECParameterSpec ecParameterSpec = privateKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(), ecDomainParameters);
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, ecPrivateKeyParameters);
            // Base64解码
            byte[] dataBytes = text.getBytes(StandardCharsets.UTF_8);
            byte[] decryptBytesBase64 = Base64.getDecoder().decode(dataBytes);
            // 解密
            byte[] decryptBytes = sm2Engine.processBlock(decryptBytesBase64, 0, decryptBytesBase64.length);
            return new String(decryptBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 生成签名
     *
     * @param text
     * @return
     */
    public static String sign(String text) {
        try {
            if (Objects.isNull(text)) {
                return null;
            }
            ECParameterSpec ecParameterSpec = privateKey.getParameters();
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(), ecDomainParameters);
            SM2Signer sm2Signer = new SM2Signer();
            sm2Signer.init(true, ecPrivateKeyParameters);
            sm2Signer.update(text.getBytes(StandardCharsets.UTF_8), 0, text.length());
            byte[] signBytes = sm2Signer.generateSignature();
            byte[] signBytesBase64 = Base64.getEncoder().encode(signBytes);
            return new String(signBytesBase64, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 验证签名
     *
     * @param text     明文数据
     * @param signText 签名的信息
     * @return
     */
    public static Boolean verify(String text, String signText) {
        if (Objects.isNull(text) || Objects.isNull(signText)) {
            return false;
        }
        // Base64解码
        byte[] bytes = signText.getBytes(StandardCharsets.UTF_8);
        byte[] signBytesBase64 = Base64.getDecoder().decode(bytes);
        ECParameterSpec ecParameterSpec = publicKey.getParameters();
        ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
        ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);
        SM2Signer sm2Signer = new SM2Signer();
        sm2Signer.init(false, ecPublicKeyParameters);
        sm2Signer.update(text.getBytes(StandardCharsets.UTF_8), 0, text.length());
        return sm2Signer.verifySignature(signBytesBase64);
    }


}