依赖:
<!--国产加密算法-->
<!-- SM加密算法依赖 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
java代码:
package com.cj.core.utils.md5;
import com.cj.core.exception.MyException;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
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.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;
/**
* @Author: LiuLei
* @Description: SM2工具类
* @Date: 2023/9/15 17:38
* @Version: 1.0
*/
public class Sm2Utils {
/**
* 编码方式
*/
private static final String ENCODING = "UTF-8";
private static String PUBLIC_KEY = "公钥";
private static String PRIVATE_KEY = "私钥";
/**
* SM2 生成公私钥
*
* @return 公私钥
*/
public static void generateKeyPair() {
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();
System.out.println("私钥:");
System.out.println(privateKey.toString(16));
System.out.println("公钥:");
System.out.println(new String(Hex.encode(publicKey.getEncoded(true))));
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
throw new MyException(e.getMessage());
}
}
/**
* 加密
* C1C2C3
* @param source
* @return
*/
public static String encrypt(String source) {
String resultStr = null;
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(PUBLIC_KEY));
try {
byte[] srcData = source.getBytes(ENCODING);
// 获取椭圆曲线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);
byte[] result = cipher.doFinal(srcData);
// 加密并编码为base64格式
resultStr = Base64.getEncoder().encodeToString(result);
} catch (Exception e) {
throw new MyException(e.getMessage());
}
return resultStr;
}
/**
* SM2加密算法
*
* @param source 明文数据
* @return
*/
public static String encrypt2(String source) {
// 获取一条SM2曲线参数
X9ECParameters sm2Parameters = GMNamedCurves.getByName("sm2p256v1");
// 构造ECC算法参数,曲线方程、椭圆曲线G点、大整数N
ECDomainParameters domainParameters = new ECDomainParameters(sm2Parameters.getCurve(), sm2Parameters.getG(), sm2Parameters.getN());
//提取公钥点
ECPoint pukPoint = sm2Parameters.getCurve().decodePoint(Hex.decode(PUBLIC_KEY));
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
ParametersWithRandom parametersWithRandom = new ParametersWithRandom(publicKeyParameters, new SecureRandom());
SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C2C3);
// 设置sm2为加密模式
sm2Engine.init(true, parametersWithRandom);
String resultStr = null;
try {
byte[] srcData = source.getBytes(ENCODING);
byte[] result = sm2Engine.processBlock(srcData, 0, srcData.length);
// 加密并编码为base64格式
resultStr = Base64.getEncoder().encodeToString(result);
} catch (Exception e) {
throw new MyException(e.getMessage());
}
return resultStr;
}
/**
* 解密
* C1C2C3
* @param source
* @return
*/
public static String decrypt(String source) {
String resultStr = null;
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(PRIVATE_KEY, 16);
try {
//内容转byte数组
byte[] srcData = Base64.getDecoder().decode(source);
// 获取椭圆曲线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);
byte[] result = cipher.doFinal(srcData);
// 解密
resultStr = new String(result, ENCODING);
} catch (Exception e) {
throw new MyException(e.getMessage());
}
return resultStr;
}
/**
* SM2解密算法
*
* @param source 密文数据
* @return
*/
public static String decrypt2(String source) {
BigInteger privateKeyD = new BigInteger(PRIVATE_KEY, 16);
//获取一条SM2曲线参数
X9ECParameters sm2Parameters = GMNamedCurves.getByName("sm2p256v1");
//构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2Parameters.getCurve(), sm2Parameters.getG(), sm2Parameters.getN());
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C2C3);
// 设置sm2为解密模式
sm2Engine.init(false, privateKeyParameters);
String resultStr = null;
try {
//内容转byte数组
byte[] srcData = Base64.getDecoder().decode(source);
byte[] result = sm2Engine.processBlock(srcData, 0, srcData.length);
// 解密
resultStr = new String(result, ENCODING);
} catch (Exception e) {
throw new MyException(e.getMessage());
}
return resultStr;
}
}
这里用了两种实现方式:Cipher 和 SM2Engine
这两种方式加密的结果可以互相通用
Cipher:这种写法我现在还没找到切换 C1C2C3 和 C!C3C2 的方式 只能默认使用C1C2C3
本文介绍了如何在Java中使用SM2加密算法,包括生成公私钥、加密和解密操作,以及使用BouncyCastleProvider和SM2Engine两种方式实现。
2630

被折叠的 条评论
为什么被折叠?



