53 lines
1.8 KiB
Java
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);
|
|
}
|
|
}
|