Files
michaelschiemer/src/Framework/Cryptography/DigitalSignatureResult.php
Michael Schiemer e30753ba0e fix: resolve RedisCache array offset error and improve discovery diagnostics
- Fix RedisCache driver to handle MGET failures gracefully with fallback
- Add comprehensive discovery context comparison debug tools
- Identify root cause: WEB context discovery missing 166 items vs CLI
- WEB context missing RequestFactory class entirely (52 vs 69 commands)
- Improved exception handling with detailed binding diagnostics
2025-09-12 20:05:18 +02:00

261 lines
6.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\Cryptography;
use InvalidArgumentException;
/**
* Digital Signature Result Value Object
*
* Represents the result of a digital signature operation including the signature
* and all metadata needed for verification.
*/
final readonly class DigitalSignatureResult
{
public function __construct(
private string $signature,
private string $algorithm,
private string $hashAlgorithm,
private int $keySize,
private ?string $curve = null
) {
if (empty($signature)) {
throw new InvalidArgumentException('Signature cannot be empty');
}
if (empty($algorithm)) {
throw new InvalidArgumentException('Algorithm cannot be empty');
}
if (empty($hashAlgorithm)) {
throw new InvalidArgumentException('Hash algorithm cannot be empty');
}
$supportedAlgorithms = ['rsa', 'ecdsa'];
if (! in_array($algorithm, $supportedAlgorithms, true)) {
throw new InvalidArgumentException('Unsupported algorithm');
}
$supportedHashAlgorithms = ['sha256', 'sha384', 'sha512', 'sha224'];
if (! in_array($hashAlgorithm, $supportedHashAlgorithms, true)) {
throw new InvalidArgumentException('Unsupported hash algorithm');
}
if ($keySize < 256) {
throw new InvalidArgumentException('Key size must be at least 256 bits');
}
}
/**
* Get the signature bytes
*/
public function getSignature(): string
{
return $this->signature;
}
/**
* Get the signature algorithm
*/
public function getAlgorithm(): string
{
return $this->algorithm;
}
/**
* Get the hash algorithm used
*/
public function getHashAlgorithm(): string
{
return $this->hashAlgorithm;
}
/**
* Get the key size in bits
*/
public function getKeySize(): int
{
return $this->keySize;
}
/**
* Get the curve name (ECDSA only)
*/
public function getCurve(): ?string
{
return $this->curve;
}
/**
* Get signature as Base64 string
*/
public function getSignatureBase64(): string
{
return base64_encode($this->signature);
}
/**
* Get signature as hexadecimal string
*/
public function getSignatureHex(): string
{
return bin2hex($this->signature);
}
/**
* Check if this is an RSA signature
*/
public function isRsa(): bool
{
return $this->algorithm === 'rsa';
}
/**
* Check if this is an ECDSA signature
*/
public function isEcdsa(): bool
{
return $this->algorithm === 'ecdsa';
}
/**
* Get signature length in bytes
*/
public function getSignatureLength(): int
{
return strlen($this->signature);
}
/**
* Export to array (for serialization)
* @return array<string, mixed>
*/
public function toArray(): array
{
$data = [
'signature' => $this->getSignatureBase64(),
'algorithm' => $this->algorithm,
'hash_algorithm' => $this->hashAlgorithm,
'key_size' => $this->keySize,
];
if ($this->curve !== null) {
$data['curve'] = $this->curve;
}
return $data;
}
/**
* Create from array (for deserialization)
* @param array<string, mixed> $data
*/
public static function fromArray(array $data): self
{
$requiredFields = ['signature', 'algorithm', 'hash_algorithm', 'key_size'];
foreach ($requiredFields as $field) {
if (! isset($data[$field])) {
throw new InvalidArgumentException("Missing required field: {$field}");
}
}
$signature = base64_decode($data['signature'], true);
if ($signature === false) {
throw new InvalidArgumentException('Invalid Base64 signature');
}
return new self(
signature: $signature,
algorithm: $data['algorithm'],
hashAlgorithm: $data['hash_algorithm'],
keySize: (int)$data['key_size'],
curve: $data['curve'] ?? null
);
}
/**
* Create from Base64 signature
*/
public static function fromBase64(
string $base64Signature,
string $algorithm,
string $hashAlgorithm,
int $keySize,
?string $curve = null
): self {
$signature = base64_decode($base64Signature, true);
if ($signature === false) {
throw new InvalidArgumentException('Invalid Base64 signature');
}
return new self(
signature: $signature,
algorithm: $algorithm,
hashAlgorithm: $hashAlgorithm,
keySize: $keySize,
curve: $curve
);
}
/**
* Create from hexadecimal signature
*/
public static function fromHex(
string $hexSignature,
string $algorithm,
string $hashAlgorithm,
int $keySize,
?string $curve = null
): self {
$signature = hex2bin($hexSignature);
if ($signature === false) {
throw new InvalidArgumentException('Invalid hexadecimal signature');
}
return new self(
signature: $signature,
algorithm: $algorithm,
hashAlgorithm: $hashAlgorithm,
keySize: $keySize,
curve: $curve
);
}
/**
* Get signature description
*/
public function getDescription(): string
{
$description = strtoupper($this->algorithm);
if ($this->algorithm === 'rsa') {
$description .= " {$this->keySize}-bit";
} elseif ($this->algorithm === 'ecdsa') {
$description .= " {$this->curve}";
}
$description .= " with " . strtoupper($this->hashAlgorithm);
return $description;
}
/**
* Get summary information (safe for logging)
* @return array<string, mixed>
*/
public function getSummary(): array
{
return [
'algorithm' => $this->algorithm,
'hash_algorithm' => $this->hashAlgorithm,
'key_size' => $this->keySize,
'curve' => $this->curve,
'signature_length' => $this->getSignatureLength(),
'description' => $this->getDescription(),
];
}
}