由于等保和多个系统间的数据传输加密, 写了一个共有的前端与后端, 后端与后端,的通用算法SM2简单加密, 不需要验签, 几行代码搞定.
引包, 测试好几遍, 这个包适合jdk1.8使用
1、后端代码示例
引包,
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.72</version>
</dependency>
没有意外就应该直接能用下面代码了
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
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.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
/**
* 简单的sm2
*/
public class SimpSM2Util {
/**
* SM2加密算法
* @param publicKey 公钥
* @param data 明文数据
* @return
*/
public static String encrypt(String publicKey, 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(publicKey));
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
// 设置sm2为加密模式
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) {
System.out.println("SM2加密时出现异常:"+e.getMessage());
}
return Hex.toHexString(arrayOfBytes);
}
/**
* SM2解密算法
* @param privateKey 私钥
* @param cipherData 密文数据
* @return
*/
public static String decrypt(String privateKey, String cipherData) {
// 使用BC库加解密时密文以04开头,传入的密文前面没有04则补上
if (!cipherData.startsWith("04")){
cipherData = "04" + cipherData;
}
byte[] cipherDataByte = Hex.decode(cipherData);
BigInteger privateKeyD = new BigInteger(privateKey, 16);
//获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
//构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
// 设置sm2为解密模式
sm2Engine.init(false, privateKeyParameters);
String result = "";
try {
byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
return new String(arrayOfBytes);
} catch (Exception e) {
System.out.println("SM2解密时出现异常:"+e.getMessage());
}
return result;
}
/*@Test
// 生成密钥
public void createKey() throws Exception{
//String M="encryption standard111111111111111111111111111111";
SimpSM2Util sm2 = new SimpSM2Util();
ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
// 获取一个椭圆曲线类型的密钥对生成器
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
// 使用SM2参数初始化生成器
kpg.initialize(sm2Spec);
// 获取密钥对
KeyPair keyPair = kpg.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
BCECPublicKey p=(BCECPublicKey)publicKey;
System.out.println("publicKey:"+Hex.toHexString(p.getQ().getEncoded(false)));
PrivateKey privateKey = keyPair.getPrivate();
BCECPrivateKey s=(BCECPrivateKey)privateKey;
System.out.println("privateKey:"+Hex.toHexString(s.getD().toByteArray()));
}*/
}
publicKey:04aa909915f87880507e3de515220cc8f82b1c5693f56a0475b3b48ff7448c229734cd724e603000dd78569faa9fbc1eeb93a6d836190a0ee734e2d9e74d804f28
privateKey:00a684d832831d5371d2ff9de6a021a33fb396451e74e0ffe0d415c298b36876fe
加密: SimpSM2Util.encrypt("共有密钥", "明文");
解密: SimpSM2Util.decrypt("私有密钥", "密文");
后端代码使用一个工具类, 可参考
import org.bouncycastle.crypto.engines.SM2Engine;
/**
* 简单单例SM2加解密, 配合前端
*/
public class LoSM2 {
private static String ECNameModel = "sm2p256v1";
private static SM2Engine.Mode CipherMode = SM2Engine.Mode.C1C3C2;
private final String privateKey;
private final String publicKey;
private LoSM2(String privateKey, String publicKey){
this.privateKey = privateKey;
this.publicKey = publicKey;
}
private volatile static LoSM2 instance = null;
public static LoSM2 getInstance(){
if(instance == null){
throw new RuntimeException("请InitKey初始化密钥!!!");
}
return instance;
}
/**
* SM2初始密钥(私钥,公钥)
* @param privateKey
* @param publicKey
* @return
*/
public static LoSM2 InitKey(String privateKey, String publicKey) {
if(instance == null){
synchronized(LoSM2.class){
if(instance == null){
instance = new LoSM2(privateKey, publicKey);
}
}
}
return instance;
}
private static class SM2SimpSelfLoader {
private static final LoSM2 instance = InitKey("", "");
}
private static boolean IsInitKey(){
if(instance == null) {
throw new RuntimeException("请InitKey初始化密钥!!!");
}else {
return true;
}
}
/**
* SM2加密
* @param cleartext 明文数据
*/
public String encrypt(String cleartext) {
if(!IsInitKey())
return "";
return SimpSM2Util.encrypt(instance.publicKey, cleartext);
}
/**
* SM2解密
* @param cipherData 密文数据
*/
public static String decrypt(String cipherData) {
if(!IsInitKey())
return "";
return SimpSM2Util.decrypt(instance.privateKey, cipherData);
}
}
2、前端代码示例
安装sm-crypto包: npm install --save sm-crypto
前端加解密更简单, 引包后就能用
let txt='简单加密不要验签' //要加密的字段
const sm2 = require('sm-crypto').sm2
const cipherMode = 1;// 1 - C1C3C2,0 - C1C2C3,默认为1
var publicKey = "04aa909915f87880507e3de515220cc8f82b1c5693f56a0475b3b48ff7448c229734cd724e603000dd78569faa9fbc1eeb93a6d836190a0ee734e2d9e74d804f28";
// 加密结果
let encryptData = sm2.doEncrypt(txt, publicKey, cipherMode);
// 解密
sm2.doDecrypt(txt, privateKey, cipherMode);
适合简单的传输加密
3、避坑指南
在引用 bcprov-jdk18on 包的时候, 有可能存在版本冲突, 或本地安全问题, 这个是我在返回切换工程遇到的问题
可以尝试把 bcprov-jdk18on-1.72.jar 加入mvn的import的sdks里面
还可以试试 mvn idea:module文章来源:https://www.toymoban.com/news/detail-592598.html
或者试试 mvn: idea:idea文章来源地址https://www.toymoban.com/news/detail-592598.html
到了这里,关于适用于前后端公用的SM2国密加密传输, JAVA + VUE的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!