maven坐标依赖
<!-- sm2加密依赖 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.2.1</version>
</dependency>
代码实现以及要求:
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.SM4;
import cn.hutool.json.JSONUtil;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.util.encoders.Hex;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @ClassName SM2Utils
* @Description 加密:1.产生随机加密key,并使用公钥进行非对称sm2加密得到加密数据,并进行base64编码;
* 2.对待加密数据通过1中的随机key进行对称sm4加密得到加密key,并进行base64编码;
* 3.对待加密数据通过sm3加密得到摘要数据,并进行base64编码;
* 4.对1、2、3中三个加密数据组合成一个加密字符串。
* 解密:1.对加密字符串按|切割为对应参数数据;
* 2.对加密的随机key使用私钥进行sm2解密得到原随机key;
* 3.使用原随机key对加密数据进行sm4解密得到原数据;
* 4.对原数据进行sm3加密得到摘要数据,与上送的摘要数据进行比较防数据篡改。
* @Author houbing
* @Date 2023/7/4 9:38
*/
public class SM2Utils {
public static void main(String[] args) {
String encData = encrypt();
System.out.println(encData);
System.out.println(validate(encData));
}
private static String publicKey = "023ecc4baa995f3c8205920ed8572528ccb31a98b06b42dcb9f0523b1c06ba619e";
private static String privateKey = "56b0199849902ad12bbf31cbb9b02707c44c60fa58043ad5aae387fdfcb3ec";
public static String encrypt() {
//取出session中用户信息,放入map并转成json字符串
Map<String,String> map = new HashMap<>();
map.put("token","sdfasdfasd");
map.put("mobilePhone","18269554985");
map.put("cifNo","888999666");
//转json字符串
String mapJson = JSONUtil.toJsonStr(map);
//产生用于作加密key的随机数 sm2key
String sm2key = UUID.randomUUID().toString().replace("-", "");;
//创建sm2 对象
SM2 sm2 = SmUtil.sm2(null, getECPublicKeyParameters());
//sm2对随机数进行非对称加密
String s2 = sm2.encryptBase64(sm2key, KeyType.PublicKey);
//sm4用随机数作为秘钥,对数据进行非对称加密
SM4 sm4 = SmUtil.sm4(Hex.decode(sm2key));
String s4 = sm4.encryptBase64(mapJson);
//sm3对数据进行摘要
String s3 = SmUtil.sm3(mapJson);
//返回组装加密字符串
return s2 + "|" + s4 + "|" + s3;
}
public static String validate(String data ) {
if(data.contains("|") && data.split("\\|").length == 3){
String[] encData = data.split("\\|");
String enc_sm4key = encData[0];
String enc_data = encData[1];
String enc_abst = encData[2];
//1.sm2解密:
//sm2对随机数进行非对称加密
ECPrivateKeyParameters ecPrivateKeyParameters = BCUtil.toSm2Params(privateKey);
//创建sm2 对象
SM2 sm2 = new SM2(ecPrivateKeyParameters, null);
//解密
String ori_sm4key = sm2.decryptStr(enc_sm4key, KeyType.PrivateKey);
//2.sm4解密
SM4 sm4 = SmUtil.sm4(Hex.decode(ori_sm4key));
String ori_data = sm4.decryptStr(Base64.decode(enc_data));
//3.sm3进行摘要验证
if(enc_abst.equals(SmUtil.sm3(ori_data))){
System.out.println("验证成功");
}
return ori_data;
}
return null;
}
/**
* 根据公钥的长度进行加工
* @return
*/
public static ECPublicKeyParameters getECPublicKeyParameters() {
//这里需要根据公钥的长度进行加工
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);
}
return ecPublicKeyParameters;
}
}