67 lines
2.1 KiB
C#
67 lines
2.1 KiB
C#
namespace StellaOps.Cryptography.Profiles.Ecdsa;
|
|
|
|
using System.Security.Cryptography;
|
|
using StellaOps.Cryptography;
|
|
using StellaOps.Cryptography.Models;
|
|
|
|
/// <summary>
|
|
/// ECDSA P-256 signer using .NET cryptography (FIPS 186-4 compliant).
|
|
/// </summary>
|
|
public sealed class EcdsaP256Signer : IContentSigner
|
|
{
|
|
private readonly ECDsa _ecdsa;
|
|
private readonly string _keyId;
|
|
private readonly TimeProvider _timeProvider;
|
|
private bool _disposed;
|
|
|
|
public string KeyId => _keyId;
|
|
public SignatureProfile Profile => SignatureProfile.EcdsaP256;
|
|
public string Algorithm => "ES256";
|
|
|
|
public EcdsaP256Signer(string keyId, ECDsa ecdsa, TimeProvider? timeProvider = null)
|
|
{
|
|
_keyId = keyId ?? throw new ArgumentNullException(nameof(keyId));
|
|
_ecdsa = ecdsa ?? throw new ArgumentNullException(nameof(ecdsa));
|
|
_timeProvider = timeProvider ?? TimeProvider.System;
|
|
|
|
if (_ecdsa.KeySize != 256)
|
|
throw new ArgumentException("ECDSA key must be P-256 (256 bits)", nameof(ecdsa));
|
|
}
|
|
|
|
public static EcdsaP256Signer Generate(string keyId, TimeProvider? timeProvider = null)
|
|
{
|
|
var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
|
|
return new EcdsaP256Signer(keyId, ecdsa, timeProvider);
|
|
}
|
|
|
|
public Task<SignatureResult> SignAsync(ReadOnlyMemory<byte> payload, CancellationToken ct = default)
|
|
{
|
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
ct.ThrowIfCancellationRequested();
|
|
|
|
var signature = _ecdsa.SignData(payload.Span, HashAlgorithmName.SHA256);
|
|
|
|
return Task.FromResult(new SignatureResult
|
|
{
|
|
KeyId = _keyId,
|
|
Profile = Profile,
|
|
Algorithm = Algorithm,
|
|
Signature = signature,
|
|
SignedAt = _timeProvider.GetUtcNow()
|
|
});
|
|
}
|
|
|
|
public byte[]? GetPublicKey()
|
|
{
|
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
return _ecdsa.ExportSubjectPublicKeyInfo();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_disposed) return;
|
|
_ecdsa?.Dispose();
|
|
_disposed = true;
|
|
}
|
|
}
|