适用于前后端公用的SM2国密加密传输, JAVA + VUE

📅 2026/7/18 9:54:15
适用于前后端公用的SM2国密加密传输, JAVA + VUE
由于等保和多个系统间的数据传输加密, 写了一个共有的前端与后端, 后端与后端,的通用算法SM2简单加密, 不需要验签, 几行代码搞定.引包, 测试好几遍, 这个包适合jdk1.8使用1、后端代码示例引包,dependency groupIdorg.bouncycastle/groupId artifactIdbcprov-jdk18on/artifactId version1.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 Mencryption 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(publicKeyHex.toHexString(p.getQ().getEncoded(false))); PrivateKey privateKey keyPair.getPrivate(); BCECPrivateKey s(BCECPrivateKey)privateKey; System.out.println(privateKeyHex.toHexString(s.getD().toByteArray())); }*/ }publicKey04aa909915f87880507e3de515220cc8f82b1c5693f56a0475b3b48ff7448c229734cd724e603000dd78569faa9fbc1eeb93a6d836190a0ee734e2d9e74d804f28privateKey00a684d832831d5371d2ff9de6a021a33fb396451e74e0ffe0d415c298b36876fe加密: 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 --savesm-crypto前端加解密更简单, 引包后就能用let txt简单加密不要验签 //要加密的字段 const sm2 require(sm-crypto).sm2 const cipherMode 1;// 1 - C1C3C20 - 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或者试试 mvn: idea:idea