64 caracteres hexadecimais). * Deve ser usado ao provisionar a integração de CRM de uma empresa. */ public static function generateSecret(): string { return bin2hex(random_bytes(32)); } /** * Calcula a assinatura hexadecimal do corpo com o segredo informado. */ public static function sign(string $body, string $secret): string { return hash_hmac(self::ALGO, $body, $secret); } /** * Verifica se a assinatura recebida corresponde ao corpo, usando o segredo. * * - Rejeita quando segredo ou assinatura estão vazios (config ausente). * - Aceita a assinatura com ou sem o prefixo "sha256=". * - Compara em tempo constante (hash_equals) para evitar timing attacks. */ public static function verify(string $body, string $secret, string $providedSignature): bool { if ($secret === '' || $providedSignature === '') { return false; } $provided = $providedSignature; if (str_starts_with($provided, self::PREFIX)) { $provided = substr($provided, strlen(self::PREFIX)); } $expected = self::sign($body, $secret); return hash_equals($expected, $provided); } }