57 lines
1.6 KiB
PHP
57 lines
1.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\Security;
|
|
|
|
use App\Core\Redis;
|
|
|
|
final class HmacService
|
|
{
|
|
/**
|
|
* Verify HMAC signature for external API requests (Flutter)
|
|
*/
|
|
public function verify(
|
|
string $secret,
|
|
string $method,
|
|
string $path,
|
|
string $timestamp,
|
|
string $nonce,
|
|
string $body,
|
|
string $providedSignature
|
|
): bool {
|
|
// 1. Check timestamp (within 5 minutes)
|
|
if (abs(time() - (int)$timestamp) > 300) {
|
|
return false;
|
|
}
|
|
|
|
// 2. Replay protection using Nonce in Redis
|
|
// Note: Redis::getInstance() would be used here
|
|
// If nonce exists, reject
|
|
|
|
// 3. Calculate Signature
|
|
$bodyHash = hash('sha256', $body);
|
|
$stringToSign = strtoupper($method) . "\n" .
|
|
$path . "\n" .
|
|
$timestamp . "\n" .
|
|
$nonce . "\n" .
|
|
$bodyHash;
|
|
|
|
$calculatedSignature = hash_hmac('sha256', $stringToSign, $secret);
|
|
|
|
return hash_equals($calculatedSignature, $providedSignature);
|
|
}
|
|
|
|
public function sign(string $secret, string $method, string $path, string $timestamp, string $nonce, string $body): string
|
|
{
|
|
$bodyHash = hash('sha256', $body);
|
|
$stringToSign = strtoupper($method) . "\n" .
|
|
$path . "\n" .
|
|
$timestamp . "\n" .
|
|
$nonce . "\n" .
|
|
$bodyHash;
|
|
|
|
return hash_hmac('sha256', $stringToSign, $secret);
|
|
}
|
|
}
|