package org.chemical;
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.SM2;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
*
*/
@Slf4j
public class Sm2Demo {
private static String publicKey;
private static String privateKey;
static {
/* 依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.0</version>
</dependency>
*/
// ***********************第一部分:生成密钥******************************
//1.生成新的公私钥
SM2 sm2 = SmUtil.sm2().initKeys();
//2. 获取公钥
publicKey = sm2.getPublicKeyBase64();
log.info("生成了公私钥,公钥为:{}", publicKey);
//3. 获取私钥
privateKey = sm2.getPrivateKeyBase64();
log.info("生成了公私钥,私钥为:{}", privateKey);
}
public static void main(String[] args) throws IOException {
// ***********************第二部分:请求发起方-处理请求数据 ******************************
// 1. 构造业务数据
Map<String, Object> body = new HashMap<>();
body.put("key1", System.nanoTime());
body.put("key2", "value2");
body.put("key3", Arrays.asList("1.1","1.2"));
// 2. 转成JSON字符串
String bodyJson = JSON.toJSONString(body);
log.info("请求体的json数据: {}", bodyJson);
// 3. 转成base64字符串
String bodyValue = Base64.encode(bodyJson);
log.info("请求体: {}", toLog(bodyValue));
// ***********************第三部分:请求发起方-生成签名 ******************************
// 获取当前时间戳(毫秒) 接收方会校验该值, 收到数据时不可超过1分钟
long currentMillis = System.currentTimeMillis();
// 获取随机数
Random random = new SecureRandom();
int nonce = random.nextInt(1000000);
// 拼接需要生成签名的数据
String value1 = String.format("%s%s%s", bodyValue, currentMillis, nonce);
// 获取数据摘要
byte[] content1 = value1.getBytes(StandardCharsets.UTF_8);
// 获取签名
SM2 privateSm2 = SmUtil.sm2(privateKey, null);
String signature = Base64.encode(privateSm2.sign(content1));
/*
将时间戳、随机数、签名值,放到请求头中
request.setHeader("X-millis", currentMillis + "");
request.setHeader("X-nonce", nonce + "");
request.setHeader("X-signature", signature);
request.setHeader("X-digest", digest);
*/
log.info("签名结果: {}, value1={}", signature, toLog(value1));
// ***********************第四部分:请求接收方-验证签名 ******************************
// 1. 从请求头获取 时间戳、随机数、签名值,从请求体获取base64的数据
String millisFromRequestHeader = currentMillis+"";
String nonceFromRequestHeader = nonce+"";
String signatureFromRequestHeader = signature;
String valueFromRequestBody = bodyValue;
// 2. 拼接数据
String value2 = String.format("%s%s%s", bodyValue, millisFromRequestHeader, nonceFromRequestHeader);
byte[] content2 = value2.getBytes(StandardCharsets.UTF_8);
// 3. 验证签名
byte[] signatureBytes = Base64.decode(signatureFromRequestHeader);
SM2 publicSm2 = SmUtil.sm2(null, publicKey);
long startTime = System.currentTimeMillis();
boolean verify = publicSm2.verify(content2, signatureBytes);
long endTime = System.currentTimeMillis();
String jsonParam = Base64.decodeStr(valueFromRequestBody);
log.info("签名验证结果: {}, 耗时: {}ms, 请求体的json数据: {}", verify, (endTime - startTime), toLog(jsonParam));
if(verify){
// 验签通过,继续业务处理
// do something ...
}else {
// 验签失败, 返回失败信息
// do something ...
}
}
static String toLog(String bodyValue){
return bodyValue.length() > 100 ? bodyValue.substring(0, 100) : bodyValue;
}
}
文章版权声明:除非注明,否则均为白茶清欢的个人技术分享原创文章,转载或复制请以超链接形式并注明出处。

还没有评论,来说两句吧...