Podpisy a algoritmy
Každý signer a verifier vzniká pre presne jeden algoritmus a pri každom volaní je naň pripnutý. Neexistuje prepínač „algorithm agility“, vďaka čomu sú útoky zámenou algoritmu štrukturálne nemožné. Všetky štyri rodiny podpisujú aj overujú:
| Algoritmus | Typ kľúča | Krivka / digest | Poznámky |
|---|---|---|---|
HS256 / HS384 / HS512 | HmacSecret | SHA-256/384/512 | Tajný kľúč s aspoň 32 / 48 / 64 náhodnými bajtmi — veľkosť hašu (RFC 7518 §3.2). |
RS256 / RS384 / RS512 | RsaKey | RSA ≥ 2048, SHA-256/384/512 | Úroveň je argument konštruktora. |
ES256 / ES384 / ES512 | EcKey | P-256 / P-384 / P-521 | Krivka kľúča určuje digest. |
EdDSA | OkpKey | Ed25519 | Vyžaduje ext-sodium. |
Výber algoritmu: pre nové asymetrické tokeny uprednostnite EdDSA alebo ES256 (malé a rýchle); RS256 použite pre kompatibilitu so systémami, ktoré vyžadujú RSA; HS256 len vtedy, keď obe strany zdieľajú tajný kľúč. Na verify() vždy pripnite presný algoritmus — balík ho nikdy neodvodzuje z tokenu.
Cez fasádu
Každý signer dostane kľúč zostavený cez Crypto::keys(); Crypto::verifier() vráti overovač riadený kľúčom:
use RoundlyConsulting\Crypto\Facades\Crypto;
use RoundlyConsulting\Crypto\Signature\Algorithm;
$hs = Crypto::hs(Crypto::keys()->hmac()->fromConfig('tokens.secret'), Algorithm::HS512); // default HS256; HS512 needs ≥ 64 bytes
$rs = Crypto::rs(Crypto::keys()->rsa()->private($privatePem)); // default RS256
$es = Crypto::es(Crypto::keys()->ec()->generate('P-384')); // ES384, from the curve
$ed = Crypto::eddsa(Crypto::keys()->ed25519()->generate()); // needs ext-sodium
$sig = $es->sign($message); // raw r‖s, as JOSE wants it
$ok = Crypto::verifier()->verify($publicKey, $message, $sig); // the key picks the algorithmKontrakty Signer a Verifier
Hs, Rs, Es aj EdDSA implementujú oba kontrakty. sign() vracia surové bajty podpisu vo formáte algoritmu — pri ECDSA je to surové JOSE r‖s, nie DER. Verifier nikdy nečíta hlavičku tokenu, aby si zvolil algoritmus:
interface Signer { public function algorithm(): Algorithm; public function sign(string $message): string; }
interface Verifier { public function algorithm(): Algorithm; public function verify(string $message, string $signature): bool; }Hs — HMAC
use RoundlyConsulting\Crypto\Signature\Hs;
use RoundlyConsulting\Crypto\Signature\Algorithm;
use RoundlyConsulting\Crypto\Signature\Key\HmacSecret;
$hs = new Hs(HmacSecret::fromString($secret), Algorithm::HS512); // default HS256; HS512 needs ≥ 64 bytes
$sig = $hs->sign($message);
$ok = $hs->verify($message, $sig); // constant-timeKonštruktor odmietne každý iný než HMAC algoritmus (AlgorithmMismatchException), takže HMAC tajný kľúč sa nikdy nedá použiť pre RS, ES ani EdDSA. Odmietne aj tajný kľúč kratší než výstup hašu danej úrovne — 48 bajtov pre HS384, 64 pre HS512 (HmacSecret::generate(64)) — výnimkou WeakKeyException, pretože verifiery, ktoré vynucujú RFC 7518 §3.2, odmietnu každý token podpísaný takým kľúčom. Overenie prebieha v konštantnom čase.
Rs — RSA
use RoundlyConsulting\Crypto\Signature\Rs;
use RoundlyConsulting\Crypto\Signature\Key\RsaKey;
$signer = new Rs(RsaKey::private($privatePem), Algorithm::RS256); // default RS256
$sig = $signer->sign($message); // needs a private key
$verifier = new Rs(RsaKey::public($publicPem), Algorithm::RS256);
$ok = $verifier->verify($message, $sig);Úroveň digestu sa určí pri vytvorení (predvolene RS256); každý RSA kľúč s 2048–8192 bitmi funguje s každou úrovňou RS. Podpisovanie iba verejným kľúčom vyhodí KeyLoadException::signingFailed(). Rs vytvorený zo súkromného kľúča aj overuje: na kontrolu sa odvodí verejná polovica, pretože ext-openssl s handle súkromného kľúča neoverí.
Es — ECDSA
use RoundlyConsulting\Crypto\Signature\Es;
use RoundlyConsulting\Crypto\Signature\Key\EcKey;
$signer = new Es(EcKey::private($p256Pem)); // algorithm is read from the key's curve
$sig = $signer->sign($message); // JOSE raw r‖s form
$verifier = new Es(EcKey::public($p256PublicPem));
$ok = $verifier->verify($message, $sig);Krivka — a teda aj veľkosť súradníc a digest — pochádza zo samotného kľúča, nikdy z hlavičky. Interné spracovanie DER je striktné a minimálne. Surové ECDSA je modifikovateľné (malleable), preto podpis nikdy nepoužívajte ako kľúč idempotencie, deduplikácie ani cache. Rovnako ako Rs aj Es vytvorený zo súkromného kľúča overuje vlastné podpisy cez odvodenú verejnú polovicu, na každej krivke.
EdDSA — Ed25519
use RoundlyConsulting\Crypto\Signature\EdDSA;
use RoundlyConsulting\Crypto\Signature\Key\OkpKey;
$key = OkpKey::generate(); // or OkpKey::fromSecretKey($sk)
$sig = (new EdDSA($key))->sign($message);
$ok = (new EdDSA(OkpKey::ed25519($key->publicKey)))->verify($message, $sig);Na overenie stačí verejný kľúč; na podpisovanie je potrebná tajná polovica. Bez ext-sodium obe operácie vyhodia Cose\UnsupportedAlgorithmException::sodiumMissing() namiesto tichého zníženia bezpečnosti. Podpis, ktorý nemá presne 64 bajtov, overením neprejde.
Overovanie riadené kľúčom
KeyVerifier pripne overenie na vlastný algoritmus verejného kľúča — ide o vstupný bod pre WebAuthn a JOSE toky riadené kľúčom. Podpisy ECDSA prijme v DER (ako ich doručuje WebAuthn) aj ako surové r‖s; ostatné algoritmy používajú svoj natívny formát:
use RoundlyConsulting\Crypto\Signature\KeyVerifier;
// The key chooses the algorithm — never a caller-supplied header:
$ok = (new KeyVerifier)->verify($publicKey, $signedData, $signature);Pomocné metódy algoritmu
use RoundlyConsulting\Crypto\Signature\Algorithm;
Algorithm::ES256->isAsymmetric(); // true
Algorithm::HS512->isHmac(); // true
Algorithm::RS384->hashName(); // 'sha384'
Algorithm::EdDSA->hashName(); // 'sha512'
Algorithm::ES256->opensslAlgorithm(); // OPENSSL_ALGO_SHA256Kódek ECDSA DER
Signature\Ec\Der prevádza medzi surovým r‖s, ktoré doručujú JOSE a WebAuthn, a ASN.1 DER, ktoré produkuje ext-openssl. Es a KeyVerifier ho používajú interne, ale je verejný — na fasáde ako Crypto::ecDer(). $coordBytes je 32 pre P-256, 48 pre P-384 a 66 pre P-521. Neplatný vstup vyhodí InvalidSignatureException:
use RoundlyConsulting\Crypto\Facades\Crypto;
use RoundlyConsulting\Crypto\Signature\Ec\Der;
$der = Crypto::ecDer()->fromRaw($rawRS, 32); // raw r‖s → DER (32 = P-256 coordinate bytes)
$raw = Crypto::ecDer()->toRaw($der, 32); // DER → raw r‖s
Crypto::ecDer()->isValid($der); // a well-formed, minimally-encoded ECDSA DER signature?
// The same static helpers, no container:
Der::fromRaw($rawRS, 48); // 48 = P-384, 66 = P-521Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.