isAvailable()) { throw new InvalidArgumentException("HMAC algorithm {$algorithm->value} is not available"); } $hmac = hash_hmac($algorithm->value, $payload, $secret); return Hash::fromString($hmac, $algorithm); } /** * Verify HMAC signature with timing-safe comparison */ public function verifyHmac(string $payload, Hash $expectedHmac, string $secret): bool { $actualHmac = $this->generateHmac($payload, $secret, $expectedHmac->getAlgorithm()); return $expectedHmac->equals($actualHmac); } /** * Verify HMAC with string signature (timing-safe) */ public function verifyHmacString(string $payload, string $signature, string $secret, HashAlgorithm $algorithm = HashAlgorithm::SHA256): bool { $expectedHmac = hash_hmac($algorithm->value, $payload, $secret); return hash_equals($expectedHmac, $signature); } }