1、实现前端加密,后端解密,前端需要引入js文件
<script src="/business/libs/crypto-js.js"></script>
// js调用方式
var encryptData = sm2Encrypt('明文', '公钥', 0);
2、后端SM2生成公私钥及解密
package wst.st.site.tools;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import wst.st.site.constant.SiteWebConstant;
/**
* SM2工具类
*
* @author wst 2023年8月21日 上午10:32:33
*
*/
public class SM2Util {
public static void main(String[] args) throws Exception {
}
/**
* 生成密钥
*
* @author wst 2023年8月21日 上午10:37:37
*/
public static void getPKs() {
try {
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
sm2ECParameters.getG(), sm2ECParameters.getN());
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
keyPairGenerator
.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
// 私钥,16进制格式,自己保存
BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
String privateKeyHex = privatekey.toString(16);
System.out.println("private Key :" + privateKeyHex);
// 公钥,16进制格式,发给前端
ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
System.out.println("public Key :" + publicKeyHex);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解密,前端登录信息解码及解码
*
* @author wst 2024年9月12日 下午1:41:47
* @param cipherData
* @return
*/
public static String decrypt(String cipherData) {
// 得到明文
String data = null;
try {
byte[] cipherDataByte = Hex.decode(cipherData);
// sm2私钥
BigInteger privateKeyD = new BigInteger(SiteWebConstant.Common.Config.Sm2_Private_Key, 16);
X9ECParameters sm2ECParameters1 = GMNamedCurves.getByName("sm2p256v1");
ECDomainParameters domainParameters1 = new ECDomainParameters(sm2ECParameters1.getCurve(),
sm2ECParameters1.getG(), sm2ECParameters1.getN());
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters1);
// 用私钥解密
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(false, privateKeyParameters);
// 前端传入的密文解密后的processBlock得到Base64格式,记得解码
// 如果只用下面给出的加密方法加密则不需要这个解码流程
byte[] arrayOfBytes = Base64.decodeBase64(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));
data = new String(arrayOfBytes);
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
/**
* 解密
* @author wst 2024年9月12日 下午2:44:39
* @param cipherData
* @return
*/
public static String sm2decrypt(String cipherData) {
String result = null;
try {
// 加密算法
String algorithm = "EC";
// 私钥Hex,还原私钥
BigInteger privateKeyD = new BigInteger(SiteWebConstant.Common.Config.Sm2_Private_Key, 16);
// 使用标准名称创建EC参数生成的参数规范
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
// 获取私钥的基本域参数
ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(), sm2ECParameters.getG(),
sm2ECParameters.getN());
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(privateKeyD, ecParameterSpec);
// 获取私钥对象
BCECPrivateKey bcecPrivateKey = new BCECPrivateKey(algorithm, ecPrivateKeySpec,
BouncyCastleProvider.CONFIGURATION);
byte[] cipherDataByte = Hex.decode(cipherData);
ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
ecParameterSpec.getG(), ecParameterSpec.getN());
// 通过私钥值和私钥基本参数创建私钥参数对象
ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
ecDomainParameters);
// 通过解密模式创建解密引擎并初始化
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(false, ecPrivateKeyParameters);
try {
byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
return new String(arrayOfBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
}
} catch (Exception e) {
}
return result;
}
/**
* 加密
* @author wst 2024年9月12日 下午2:42:21
* @param data
* @return
*/
public static String encrypt(String data){
// 获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
// 构造ECC算法参数,曲线方程、椭圆曲线G点、大整数N
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
//提取公钥点
ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(SiteWebConstant.Common.Config.Sm2_Public_Key));
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
byte[] arrayOfBytes = null;
try {
byte[] in = data.getBytes();
arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
} catch (Exception e) {
e.printStackTrace();
}
return Hex.toHexString(arrayOfBytes);
}
}