org.bouncycastle
bcprov-jdk15on
1.68
cn.hutool
hutool-all
5.7.22
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.ECKeyUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* SM2非对称加密工具类
*/
public class SM2Utils {
public static void main(String[] args) throws Exception {
SM2 sm2 = SmUtil.sm2();
//生成后端公钥和私钥
String publicKey = sm2.getPublicKeyBase64();
String privateKey = sm2.getPrivateKeyBase64();
//生成前端公钥和私钥
String web_publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false)).toUpperCase();
String web_privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey())).toUpperCase();
System.out.println("加密后:" + SM2Utils.encrypt(publicKey, "测试"));
System.out.println("加密内容:" + SM2Utils.decrypt(privateKey, SM2Utils.encrypt(publicKey, "测试")));
//签名
byte[] signByte = sm2.sign("测试".getBytes());
//验签
System.out.println(sm2.verify("测试".getBytes(), signByte));
//签名
String sign = SM2Utils.sign(privateKey, "测试");
//验签
System.out.println(SM2Utils.verify("测试", publicKey, sign));
//证书验签
System.out.println(SM2Utils.certVerify("XXXX", "测试", "xxx"));
}
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 生成秘钥对
* @return 公钥和私钥
*/
public static Map generatorKey() {
SM2 sm2 = SmUtil.sm2();
String publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false)).toUpperCase();
String privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey())).toUpperCase();
Map map = new HashMap<>();
map.put("publicKey", publicKey);
map.put("privateKey", privateKey);
return map;
}
/**
* 加密
*
* @param publicKey 公钥
* @param data 明文
* @return 密文
*/
public static String encrypt(String publicKey, String data) {
return SmUtil.sm2(null, publicKey)
// 不写默认就是C1C3C2
.setMode(SM2Engine.Mode.C1C3C2)
.encryptHex(data.getBytes(), KeyType.PublicKey)
// 为保障前后端逻辑一致,去掉密文前面04
.substring(2);
}
/**
* 解密
*
* @param privateKey 私钥
* @param data 密文
* @return 明文
*/
public static String decrypt(String privateKey, String data) {
// 为保障前后端逻辑一致,统一加上04
data = "04" + data;
return SmUtil.sm2(privateKey, null)
// 不写默认就是C1C3C2
.setMode(SM2Engine.Mode.C1C3C2)
.decryptStr(data, KeyType.PrivateKey);
}
//签名
public static String sign(String privateKey, String content) throws CryptoException, NoSuchAlgorithmException {
ECPrivateKeyParameters privateKeyParams = ECKeyUtil.decodePrivateKeyParams(SecureUtil.decode(privateKey));
//待签名内容转为字节数组
byte[] message = content.getBytes();
//获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
//构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
sm2ECParameters.getG(), sm2ECParameters.getN());
BigInteger privateKeyD = new BigInteger(privateKeyParams.getD().toString(16), 16);
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
//创建签名实例
SM2Signer sm2Signer = new SM2Signer();
//ID默认值:1234567812345678
sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")), Strings.toByteArray("1234567812345678")));
sm2Signer.update(message, 0, message.length);
byte[] signBytes = sm2Signer.generateSignature();
String sign = Hex.toHexString(signBytes);
return sign;
}
//验签
public static boolean verify(String content, String publicKey, String sign) {
ECPublicKeyParameters publicKeyKeyParams = ECKeyUtil.decodePublicKeyParams(SecureUtil.decode(publicKey));
//待签名内容
byte[] message = content.getBytes();
byte[] signData = Hex.decode(sign);
// 获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
// 构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
sm2ECParameters.getG(),
sm2ECParameters.getN());
//提取公钥点
ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(new String(Hex.encode(publicKeyKeyParams.getQ().getEncoded(true)))));
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
//创建签名实例
SM2Signer sm2Signer = new SM2Signer();
//ID默认值:1234567812345678
ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray("1234567812345678"));
sm2Signer.init(false, parametersWithID);
sm2Signer.update(message, 0, message.length);
//验证签名结果
boolean verify = sm2Signer.verifySignature(signData);
return verify;
}
/**
* 证书验签
*
* @param certStr 证书串
* @param plaintext 签名原文
* @param signValueStr 签名产生签名值
* @return
*/
public static boolean certVerify(String certStr, String plaintext, String signValueStr) throws Exception {
byte[] signValue = Base64.getDecoder().decode(signValueStr);
/*
* 解析证书
*/
CertificateFactory CF = CertificateFactory.getInstance("X.509", "BC");
ByteArrayInputStream byteArrayIn = new ByteArrayInputStream(Base64.getDecoder().decode(certStr));
Certificate certificate = CF.generateCertificate(byteArrayIn);
byteArrayIn.close();
// 验证签名
Signature signature = Signature.getInstance("SM3withSM2");
signature.initVerify(certificate.getPublicKey());
signature.update(plaintext.getBytes());
return signature.verify(signValue);
}
}
npm install sm-crypto --save
const sm2 = require('sm-crypto').sm2;
sm2.doEncrypt(data, web_publicKey);
sm2.doDecrypt(base64_pwd, web_privateKey);