首先引入maven
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.69</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
直接上代码
import lombok.Data;
/**
* 1. @description:
* 2. @author: xh
* 3. @time: 2022/7/14
*/
@Data
public class SMKeyPair {
//私钥
private String priKey;
//公钥
private String pubKey;
public SMKeyPair(String priKey, String pubKey) {
this.priKey = priKey;
this.pubKey = pubKey;
}
}
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* 1. @description: 国密SM2加解密
* 2. @author: xh
* 3. @time: 2022/7/14
*/
public class Sm2Utils {
/**
* 生成公私钥对(默认压缩公钥)
* @return
*/
public static SMKeyPair genKeyPair() {
SM2 sm2 = SmUtil.sm2();
//这里会自动生成对应的随机秘钥对
byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
//这里默认公钥压缩 公钥的第一个字节用于表示是否压缩 02或者03表示是压缩公钥,04表示未压缩公钥
byte[] publicKey = BCUtil.encodeECPublicKey(sm2.getPublicKey());
//这里得到未压缩的公钥 byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
String priKey = HexUtil.encodeHexStr(privateKey);
String pubKey = HexUtil.encodeHexStr(publicKey);
return new SMKeyPair(priKey, pubKey);
}
/**
* SM2加密算法
* @param publicKey 公钥
* @param text 数据
* @return
*/
public static String encrypt(String publicKey, String text) {
ECPublicKeyParameters ecPublicKeyParameters = null;
//这里需要根据公钥的长度进行加工
if (publicKey.length() == 130) {
//这里需要去掉开始第一个字节 第一个字节表示标记
publicKey = publicKey.substring(2);
String xhex = publicKey.substring(0, 64);
String yhex = publicKey.substring(64, 128);
ecPublicKeyParameters = BCUtil.toSm2Params(xhex, yhex);
} else {
PublicKey p = BCUtil.decodeECPoint(publicKey, SmUtil.SM2_CURVE_NAME);
ecPublicKeyParameters = BCUtil.toParams(p);
}
//创建sm2 对象
SM2 sm2 = new SM2(null, ecPublicKeyParameters);
// 公钥加密
return sm2.encryptBcd(text, KeyType.PublicKey);
}
/**
* SM2加密算法
* @param publicKey 公钥
* @param text 明文数据
* @return
*/
public static String encrypt(PublicKey publicKey, String text) {
ECPublicKeyParameters ecPublicKeyParameters = BCUtil.toParams(publicKey);
//创建sm2 对象
SM2 sm2 = new SM2(null, ecPublicKeyParameters);
// 公钥加密
return sm2.encryptBcd(text, KeyType.PublicKey);
}
/**
* SM2解密算法
* @param privateKey 私钥
* @param cipherData 密文数据
* @return
*/
public static String decrypt(String privateKey, String cipherData) {
ECPrivateKeyParameters ecPrivateKeyParameters = BCUtil.toSm2Params(privateKey);
//创建sm2 对象
SM2 sm2 = new SM2(ecPrivateKeyParameters, null);
// 私钥解密
return StrUtil.utf8Str(sm2.decryptFromBcd(cipherData, KeyType.PrivateKey));
}
/**
* SM2解密算法
* @param privateKey 私钥
* @param cipherData 密文数据
* @return
*/
public static String decrypt(PrivateKey privateKey, String cipherData) {
ECPrivateKeyParameters ecPrivateKeyParameters = BCUtil.toParams(privateKey);
//创建sm2 对象
SM2 sm2 = new SM2(ecPrivateKeyParameters, null);
// 私钥解密
return StrUtil.utf8Str(sm2.decryptFromBcd(cipherData, KeyType.PrivateKey));
}
/**
* 私钥签名
* @param privateKey 私钥
* @param content 待签名内容
* @return
*/
public static String sign(String privateKey, String content) {
ECPrivateKeyParameters ecPrivateKeyParameters = BCUtil.toSm2Params(privateKey);
//创建sm2 对象
SM2 sm2 = new SM2(ecPrivateKeyParameters, null);
String sign = sm2.signHex(HexUtil.encodeHexStr(content));
return sign;
}
/**
* 验证签名
* @param publicKey 公钥
* @param content 待签名内容
* @param sign 签名值
* @return
*/
public static boolean verify(String publicKey, String content, String sign) {
ECPublicKeyParameters ecPublicKeyParameters = null;
//这里需要根据公钥的长度进行加工
if (publicKey.length() == 130) {
//这里需要去掉开始第一个字节 第一个字节表示标记
publicKey = publicKey.substring(2);
String xhex = publicKey.substring(0, 64);
String yhex = publicKey.substring(64, 128);
ecPublicKeyParameters = BCUtil.toSm2Params(xhex, yhex);
} else {
PublicKey p = BCUtil.decodeECPoint(publicKey, SmUtil.SM2_CURVE_NAME);
ecPublicKeyParameters = BCUtil.toParams(p);
}
//创建sm2 对象
SM2 sm2 = new SM2(null, ecPublicKeyParameters);
boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(content), sign);
return verify;
}
public static void main(String[] args) {
SMKeyPair smKeyPair = genKeyPair();
String priKey = smKeyPair.getPriKey();
System.out.println("私钥"+ priKey);
String pubKey = smKeyPair.getPubKey();
System.out.println("公钥"+ pubKey);
//明文
String text = "123123123";
System.out.println("测试明文文本" + text);
//签名测试
String sign = sign(priKey, text);
System.out.println("生成签名" + sign);
//验签测试
boolean verify = verify(pubKey, text, sign);
System.out.println("验签结果" + verify);
//加解密测试
String encryptData = encrypt(pubKey, text);
System.out.println("加密结果" + encryptData);
String decryptData = decrypt(priKey, encryptData);
System.out.println("解密结果" + decryptData);
}
}
私钥d1197a8dc58791f3d62c28a3447089f98fb9cf46f4a0608b6db9f119b939c16f
公钥035a5f4a04c818e9721ca88783c49ee391e3c4b42422fd7ac83a1abdb6ca5dd546
测试明文文本123123123
生成签名3045022100c87cf39c28e353937540acf14d87451722289098de6fb8ac0e1a33d7082a7daf022031786170b1bde6fbc86f10e3c0a32b428baf5071c18c5c2b1f378ab4fab440c6
验签结果true
加密结果04782AA43A09A3716819B7DE201B962EBE7A48A3471B1963DDAFB723EC20A4F20BECB12201A3A6477E226130E5DB9BF786C9EBA5BC82912D7AE240025318140649F9B364ECC6F61412C561556768D9C2BC7B9CDE264F4B62153711F0991EECAA405982BE5AE2F6D2C3E2
解密结果123123123