Java实现SM3签名摘要生成(报文+口令)完整方案
1. 实现思路
要实现「报文+口令生成SM3签名摘要」需要:
- 将原始报文和口令按约定规则拼接
- 使用SM3算法生成摘要(32字节十六进制字符串)
- 可选添加时间戳等防重放攻击要素
2. 完整代码实现
(1)SM3签名工具类
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.util.encoders.Hex;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
public class Sm3SignUtil {
/**
* 生成带口令的SM3签名
* @param message 原始报文
* @param password 签名口令
* @return 32字节十六进制签名摘要
*/
public static String generateSignature(String message, String password) {
// 1. 拼接报文和口令(按业务约定格式)
String rawData = message + "|" + password;
// 2. 计算SM3摘要
SM3Digest digest = new SM3Digest();
byte[] bytes = rawData.getBytes(StandardCharsets.UTF_8);
digest.update(bytes, 0, bytes.length);
byte[] hash = new byte[digest.getDigestSize()];
digest.doFinal(hash, 0);
return Hex.toHexString(hash);
}
/**
* 生成带时间戳的签名(防重放)
* @param timestamp 时间戳(秒级)
*/
public static String generateSignatureWithTimestamp(String message, String password, long timestamp) {
String rawData = message + "|" + password + "|" + timestamp;
// ...剩余逻辑同上...
}
/**
* 验证签名
* @return 是否验证通过
*/
public static boolean verifySignature(String message, String password, String signature) {
String calculatedSig = generateSignature(message, password);
return calculatedSig.equals(signature);
}
}
(2)使用示例
public class Main {
public static void main(String[] args) {
String originalMessage = "amount=100&orderId=123456";
String password = "mySecret@2023";
// 1. 生成签名
String signature = Sm3SignUtil.generateSignature(originalMessage, password);
System.out.println("SM3签名结果: " + signature);
// 2. 验证签名
boolean isValid = Sm3SignUtil.verifySignature(originalMessage, password, signature);
System.out.println("签名验证结果: " + isValid);
}
}
输出示例:
SM3签名结果: 6607f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0
签名验证结果: true
3. 关键增强功能
(1)添加时间戳防重放
// 生成带时间戳的签名
long timestamp = Instant.now().getEpochSecond();
String signature = Sm3SignUtil.generateSignatureWithTimestamp(
originalMessage,
password,
timestamp
);
// 验证时检查时间戳有效性(如5分钟内有效)
boolean isExpired = (Instant.now().getEpochSecond() - timestamp) > 300;
(2)加盐增强安全性
public static String generateSignatureWithSalt(String message, String password, String salt) {
String rawData = message + "|" + password + "|" + salt;
// ...SM3计算逻辑...
}
(3)二进制数据支持
public static String generateSignature(byte[] messageBytes, String password) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(messageBytes);
bos.write(password.getBytes(StandardCharsets.UTF_8));
byte[] combined = bos.toByteArray();
SM3Digest digest = new SM3Digest();
digest.update(combined, 0, combined.length);
// ...后续计算...
}
4. 生产环境建议
-
口令管理:
- 口令不应硬编码,建议从安全配置中心获取
- 定期轮换口令(如每月更换)
-
签名规范:
// 推荐拼接格式(避免歧义) String format = "%s||%s||%d"; // 报文||口令||时间戳 -
性能优化:
// 使用线程局部变量复用SM3Digest实例(需测试线程安全性) private static final ThreadLocal<SM3Digest> digestHolder = ThreadLocal.withInitial(SM3Digest::new); -
审计日志:
- 记录签名生成/验证的关键参数(脱敏后)
5. 完整流程图示
原始报文 + 口令 → 按规则拼接 → SM3哈希计算 → 32字节签名摘要
6. 与加密方案的结合使用
典型安全通信流程:
-
客户端:
String signature = Sm3SignUtil.generateSignature(message, password); String encrypted = Sm4WithBase64Util.encryptWithBase64(message, key, iv); // 发送encrypted和signature -
服务端:
String decrypted = Sm4WithBase64Util.decryptWithBase64(encrypted, key, iv); boolean isValid = Sm3SignUtil.verifySignature(decrypted, password, signature);
375

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



