基础概念
SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。
SM2算法是在国际标准的ECC椭圆曲线密码理论基础上进行自主研发设计,具备ECC算法的性能特点并实现优化改进。
依赖
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.5</version>
</dependency>
</dependencies>
生成公私钥工具类
public static Map<String, String> generateSmKeyBase64() throws Exception {
Map<String, String> map = new HashMap<>(2);
// 生成公私钥对象
SecureRandom secureRandom = new SecureRandom();
ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
// 获取一个椭圆曲线类型的秘钥对生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
// 使用SM2的算法区域初始化秘钥生成器
keyPairGenerator.initialize(sm2Spec, secureRandom);
// 获取秘钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 获取公钥
PublicKey keyPairPublic = keyPair.getPublic();
byte[] encodedPublicKey = keyPairPublic.getEncoded();
byte[] bytePublicKey = Base64.getEncoder().encode(encodedPublicKey);
String publicKey = new String(bytePublicKey, StandardCharsets.UTF_8);
map.put("publicKey", publicKey);
// 获取私钥
PrivateKey keyPairPrivate = keyPair.getPrivate();
byte[] encodedPrivateKey = keyPairPrivate.getEncoded();
byte[] bytePrivateKey = Base64.getEncoder().encode(encodedPrivateKey);
String privateKey = new String(bytePrivateKey, StandardCharsets.UTF_8);
map.put("privateKey", privateKey);
return map;
}
加解密工具类
/**
* @author 苦瓜不苦
* @date 2022/12/13 15:29
**/
public class SM2Util {
private static BCECPublicKey publicKey;
private static BCECPrivateKey privateKey;
private final static String PRIVATE_KEY = "xxxxx";
private final static String PUBLIC_KEY = "xxxxx";
static {
try {
publicKey = (BCECPublicKey) SM2Util.createPublicKey(PUBLIC_KEY);
privateKey = (BCECPrivateKey) SM2Util.createPrivateKey(PRIVATE_KEY);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将Base64转码的公钥串,转换为公钥对象
*
* @param publicKey Base64公钥串
* @return
* @throws Exception
*/
public static PublicKey createPublicKey(String publicKey) throws Exception {
// 解码Base64
byte[] decode = Base64.getDecoder().decode(publicKey);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(decode);
KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
return keyFactory.generatePublic(publicKeySpec);
}
/**
* 将Base64转码的私钥串,转换为私钥对象
*
* @param privateKey Base64私钥串
* @return
* @throws Exception
*/
public static PrivateKey createPrivateKey(String privateKey) throws Exception {
// 解码Base64
byte[] decode = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode);
KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
}
/**
* SM2数据加密
*
* @param text 未加密数据
* @return SM2加密后的字符串
*/
public static String encrypt(String text) {
try {
if (Objects.isNull(text)) {
return null;
}
ECParameterSpec ecParameterSpec = publicKey.getParameters();
ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
// 加密
byte[] dataBytes = text.getBytes(StandardCharsets.UTF_8);
byte[] encryptBytes = sm2Engine.processBlock(dataBytes, 0, dataBytes.length);
// Base64编码
byte[] encryptBytesBase64 = Base64.getEncoder().encode(encryptBytes);
return new String(encryptBytesBase64, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* SM2数据解密
*
* @param text 加密数据
* @return SM2解密后的字符串
*/
public static String decrypt(String text) {
try {
if (Objects.isNull(text)) {
return null;
}
ECParameterSpec ecParameterSpec = privateKey.getParameters();
ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(), ecDomainParameters);
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(false, ecPrivateKeyParameters);
// Base64解码
byte[] dataBytes = text.getBytes(StandardCharsets.UTF_8);
byte[] decryptBytesBase64 = Base64.getDecoder().decode(dataBytes);
// 解密
byte[] decryptBytes = sm2Engine.processBlock(decryptBytesBase64, 0, decryptBytesBase64.length);
return new String(decryptBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 生成签名
*
* @param text
* @return
*/
public static String sign(String text) {
try {
if (Objects.isNull(text)) {
return null;
}
ECParameterSpec ecParameterSpec = privateKey.getParameters();
ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(), ecDomainParameters);
SM2Signer sm2Signer = new SM2Signer();
sm2Signer.init(true, ecPrivateKeyParameters);
sm2Signer.update(text.getBytes(StandardCharsets.UTF_8), 0, text.length());
byte[] signBytes = sm2Signer.generateSignature();
byte[] signBytesBase64 = Base64.getEncoder().encode(signBytes);
return new String(signBytesBase64, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 验证签名
*
* @param text 明文数据
* @param signText 签名的信息
* @return
*/
public static Boolean verify(String text, String signText) {
if (Objects.isNull(text) || Objects.isNull(signText)) {
return false;
}
// Base64解码
byte[] bytes = signText.getBytes(StandardCharsets.UTF_8);
byte[] signBytesBase64 = Base64.getDecoder().decode(bytes);
ECParameterSpec ecParameterSpec = publicKey.getParameters();
ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);
SM2Signer sm2Signer = new SM2Signer();
sm2Signer.init(false, ecPublicKeyParameters);
sm2Signer.update(text.getBytes(StandardCharsets.UTF_8), 0, text.length());
return sm2Signer.verifySignature(signBytesBase64);
}
}