Files
baiyue-firstleg/common-event-contract/src/main/java/com/baiyue/common/event/EventPayloadHash.java
T
2026-07-30 18:01:36 +08:00

53 lines
1.8 KiB
Java

package com.baiyue.common.event;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
import java.util.Locale;
import java.util.regex.Pattern;
/**
* 事件负载 SHA-256 摘要工具。
*/
public final class EventPayloadHash {
private static final Pattern HASH_PATTERN = Pattern.compile("^sha256:[0-9a-fA-F]{64}$");
private EventPayloadHash() {
}
/**
* 计算调用方提供的规范化负载字节摘要。
*/
public static String sha256(byte[] canonicalPayload) {
if (canonicalPayload == null) {
throw new IllegalArgumentException("规范化负载字节不能为空");
}
try {
byte[] digest = MessageDigest.getInstance("SHA-256").digest(canonicalPayload);
return "sha256:" + HexFormat.of().formatHex(digest);
} catch (NoSuchAlgorithmException exception) {
throw new IllegalStateException("当前运行环境不支持 SHA-256", exception);
}
}
/**
* 判断摘要是否符合约定格式。
*/
public static boolean hasValidFormat(String value) {
return value != null && HASH_PATTERN.matcher(value).matches();
}
/**
* 使用常量时间比较校验规范化负载字节与摘要是否一致。
*/
public static boolean matches(byte[] canonicalPayload, String expectedHash) {
if (canonicalPayload == null || !hasValidFormat(expectedHash)) {
return false;
}
byte[] actual = sha256(canonicalPayload).getBytes(StandardCharsets.US_ASCII);
byte[] expected = expectedHash.toLowerCase(Locale.ROOT).getBytes(StandardCharsets.US_ASCII);
return MessageDigest.isEqual(actual, expected);
}
}