feat(cloud): HMAC sign/verify matching P1-A edge contract

This commit is contained in:
유창욱 2026-07-11 23:21:00 +09:00
parent 50cb2cfe82
commit 8e62304471
2 changed files with 42 additions and 0 deletions

View file

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace App\Security;
final class Hmac
{
public static function sign(string $secret, string $nonce, string $ts, string $body): string
{
return hash_hmac('sha256', $nonce . $ts . $body, $secret);
}
public static function verify(string $secret, string $nonce, string $ts, string $body, string $sig): bool
{
$expected = self::sign($secret, $nonce, $ts, $body);
return hash_equals($expected, $sig);
}
}

25
cloud/tests/HmacTest.php Normal file
View file

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace App\Tests;
use App\Security\Hmac;
use PHPUnit\Framework\TestCase;
final class HmacTest extends TestCase
{
public function testSignMatchesPythonEdgeContract(): void
{
// P1-A edge/alert.py::sign = HMAC-SHA256(nonce+ts+body, secret) hex
$sig = Hmac::sign('secret', 'n1', '1000.0', '{"a":1}');
$expected = hash_hmac('sha256', 'n1' . '1000.0' . '{"a":1}', 'secret');
$this->assertSame($expected, $sig);
$this->assertSame(64, strlen($sig));
}
public function testVerifyTrueOnMatchFalseOnTamper(): void
{
$sig = Hmac::sign('secret', 'n1', '1000.0', 'body');
$this->assertTrue(Hmac::verify('secret', 'n1', '1000.0', 'body', $sig));
$this->assertFalse(Hmac::verify('secret', 'n1', '1000.0', 'body-TAMPERED', $sig));
$this->assertFalse(Hmac::verify('wrong', 'n1', '1000.0', 'body', $sig));
}
}