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); } }