import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.ArrayUtils;
public class AurinkoValidator {
private static final String HMAC_ALGO = "HmacSHA256";
private static final String VERSION = "v0";
public boolean isValidRequest(String signingSecret, String timestamp, String headerSignature, byte[] rawBody) {
try {
// 1. Prepare the prefix: "v0:timestamp:"
String prefix = VERSION + ":" + timestamp + ":";
byte[] prefixBytes = prefix.getBytes(StandardCharsets.UTF_8);
// 2. Concatenate prefix bytes with raw body bytes
byte[] dataToSign = ArrayUtils.addAll(prefixBytes, rawBody);
// 3. Initialize HMAC SHA256 with your Secret
SecretKeySpec secretKeySpec = new SecretKeySpec(
signingSecret.getBytes(StandardCharsets.UTF_8),
HMAC_ALGO
);
Mac mac = Mac.getInstance(HMAC_ALGO);
mac.init(secretKeySpec);
// 4. Compute the hash
byte[] computedHashBytes = mac.doFinal(dataToSign);
String computedSignature = Hex.encodeHexString(computedHashBytes);
// 5. Compare computed signature with the header
// Use MessageDigest.isEqual for a time-constant comparison (prevents timing attacks)
return java.security.MessageDigest.isEqual(
computedSignature.getBytes(StandardCharsets.UTF_8),
headerSignature.getBytes(StandardCharsets.UTF_8)
);
} catch (Exception e) {
// Log the error and reject the request
return false;
}
}
}