SM2加密实现之JAVA方式

package com.xxx.tax.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * SM2加密
 *
 * @author hcf
 * @date 2021/9/1 14:31
 */
@Slf4j
public class Sm2Utils {

    /**
     * SM2 生成公私钥
     *
     * @return 公私钥
     */
    public static Map<String, String> generateKeyPair() {
        Map<String, String> resultMap = new HashMap<>(2);
        try {
            BouncyCastleProvider provider = new BouncyCastleProvider();

            // 获取椭圆曲线相关生成参数规格
            ECGenParameterSpec genParameterSpec = new ECGenParameterSpec("sm2p256v1");
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", provider);

            // 使用SM2的算法区域初始化密钥生成器
            keyPairGenerator.initialize(genParameterSpec, new SecureRandom());

            // 生成密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            BCECPrivateKey exPrivateKey = (BCECPrivateKey) keyPair.getPrivate();
            BCECPublicKey ecPublicKey = (BCECPublicKey) keyPair.getPublic();

            // 解密密钥
            BigInteger privateKey = exPrivateKey.getD();
            // 加密密钥
            ECPoint publicKey = ecPublicKey.getQ();

            resultMap.put("privateKey", privateKey.toString(16));
            resultMap.put("publicKey", new String(Hex.encode(publicKey.getEncoded(true))));
        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
            log.info("NoSuchAlgorithmException | InvalidAlgorithmParameterException {}", e.getMessage(), e);
        }
        return resultMap;
    }
    
	public static String printHexString(byte[] b) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                builder.append('0'+hex);
                hex = '0' + hex;
            }else {
            	 builder.append(hex);
            }
            //System.out.print(hex.toLowerCase());
           
        }
        System.out.println(builder.toString());
        return builder.toString();
    }

    /**
     * sm2 加密
     *
     * @param publicKey 公钥
     * @param content   内容
     * @return 密文
     */
    public static String encrypt(String publicKey, String content) {
        String contentEncrypt = StringUtils.EMPTY;
        try {
            BouncyCastleProvider provider = new BouncyCastleProvider();
            // 获取SM2相关参数
            X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
            // 椭圆曲线参数规格
            ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
            // 将公钥HEX字符串转换为椭圆曲线对应的点
            ECPoint ecPoint = parameters.getCurve().decodePoint(Hex.decode(publicKey));
            // 获取椭圆曲线KEY生成器
            KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
            // 将椭圆曲线点转为公钥KEY对象
            BCECPublicKey bcecPublicKey = (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));

            // 获取SM2加密器
            Cipher cipher = Cipher.getInstance("SM2", provider);
            // 初始化为加密模式
            cipher.init(Cipher.ENCRYPT_MODE, bcecPublicKey);
            // 加密并编码为base64格式
            contentEncrypt = Base64.getEncoder().encodeToString(cipher.doFinal(content.getBytes()));

        } catch (Exception e) {
            log.info("SM2Utils.encrypt(java.lang.String, java.lang.String) error {}", e.getMessage(), e);
        }
        
        return printHexString(contentEncrypt.getBytes());
        //return contentEncrypt;
    }

    /**
     * sm2 加密
     *
     * @param publicKey 公钥
     * @param content   内容
     * @return 密文
     */
    public static String encrypt(String publicKey, byte[] content) {
        return encrypt(publicKey, new String(content));
    }

    /**
     * sm2 加密
     *
     * @param privateKey     私钥
     * @param contentDecrypt 密文
     * @return 明文
     */
    public static String decrypt(String privateKey, String contentDecrypt) {
        String content = StringUtils.EMPTY;
        try {
            BouncyCastleProvider provider = new BouncyCastleProvider();
            // 获取SM2相关参数
            X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
            // 椭圆曲线参数规格
            ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
            // 将私钥HEX字符串转换为X值
            BigInteger bigInteger = new BigInteger(privateKey, 16);
            // 获取椭圆曲线KEY生成器
            KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
            // 将X值转为私钥KEY对象
            BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger, ecParameterSpec));

            // 获取SM2加密器
            Cipher cipher = Cipher.getInstance("SM2", provider);
            // 初始化为加密模式
            cipher.init(Cipher.DECRYPT_MODE, bcecPrivateKey);
            // 解密
            content = new String(cipher.doFinal(Base64.getDecoder().decode(contentDecrypt)));

        } catch (Exception e) {
            log.info("SM2Utils.encrypt(java.lang.String, java.lang.String) error {}", e.getMessage(), e);
        }
        return content;
    }

    /**
     * sm2 加密
     *
     * @param privateKey     私钥
     * @param contentDecrypt 密文
     * @return 明文
     */
    public static String decrypt(String privateKey, byte[] contentDecrypt) {
        return decrypt(privateKey, new String(contentDecrypt));
    }


    public static void main(String[] args) {
    	
    	String publicKey = "043048E9968B72DDF70983B8E305217D94C1E02A5BD4875B625ACC3B13512641A7AD7DF0A1A39F453675EB4B085D8B9E05433E91DBE716E80A7219C2485F28B01F";
        System.out.println(encrypt(publicKey, "8F6190402EC4F423"));
    }

}

如有问题,请私信。

xObP8s/gudi/zrPMoaJKU7K5u7e+s7/Os8yhokpBVkHP4LnYv86zzMjn0OjSqtKyv8nS1MGqz7VRUaGjDQoNCtf31d8gUVEgNDA0NTQwMjI5

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liberty888

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值