up
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using StellaOps.Cryptography;
|
||||
|
||||
namespace StellaOps.Excititor.WebService.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service interface for hashing operations in Excititor (CRYPTO-90-001).
|
||||
/// Abstracts hashing implementation to support GOST/SM algorithms via ICryptoProviderRegistry.
|
||||
/// </summary>
|
||||
public interface IVexHashingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Compute hash of a UTF-8 encoded string.
|
||||
/// </summary>
|
||||
string ComputeHash(string value, string algorithm = "sha256");
|
||||
|
||||
/// <summary>
|
||||
/// Compute hash of raw bytes.
|
||||
/// </summary>
|
||||
string ComputeHash(ReadOnlySpan<byte> data, string algorithm = "sha256");
|
||||
|
||||
/// <summary>
|
||||
/// Try to compute hash of raw bytes with stack-allocated buffer optimization.
|
||||
/// </summary>
|
||||
bool TryComputeHash(ReadOnlySpan<byte> data, Span<byte> destination, out int bytesWritten, string algorithm = "sha256");
|
||||
|
||||
/// <summary>
|
||||
/// Format a hash digest with algorithm prefix.
|
||||
/// </summary>
|
||||
string FormatDigest(string algorithm, ReadOnlySpan<byte> digest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IVexHashingService"/> that uses ICryptoProviderRegistry
|
||||
/// when available, falling back to System.Security.Cryptography for SHA-256.
|
||||
/// </summary>
|
||||
public sealed class VexHashingService : IVexHashingService
|
||||
{
|
||||
private readonly ICryptoProviderRegistry? _registry;
|
||||
|
||||
public VexHashingService(ICryptoProviderRegistry? registry = null)
|
||||
{
|
||||
_registry = registry;
|
||||
}
|
||||
|
||||
public string ComputeHash(string value, string algorithm = "sha256")
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
return ComputeHash(bytes, algorithm);
|
||||
}
|
||||
|
||||
public string ComputeHash(ReadOnlySpan<byte> data, string algorithm = "sha256")
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[64]; // Large enough for SHA-512 and GOST
|
||||
if (!TryComputeHash(data, buffer, out var written, algorithm))
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to compute {algorithm} hash.");
|
||||
}
|
||||
|
||||
return FormatDigest(algorithm, buffer[..written]);
|
||||
}
|
||||
|
||||
public bool TryComputeHash(ReadOnlySpan<byte> data, Span<byte> destination, out int bytesWritten, string algorithm = "sha256")
|
||||
{
|
||||
bytesWritten = 0;
|
||||
|
||||
// Try to use crypto provider registry first for pluggable algorithms
|
||||
if (_registry is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var resolution = _registry.ResolveHasher(algorithm);
|
||||
var hasher = resolution.Hasher;
|
||||
var result = hasher.ComputeHash(data);
|
||||
if (result.Length <= destination.Length)
|
||||
{
|
||||
result.CopyTo(destination);
|
||||
bytesWritten = result.Length;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fall through to built-in implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to System.Security.Cryptography for standard algorithms
|
||||
var normalizedAlgorithm = algorithm.ToLowerInvariant().Replace("-", string.Empty);
|
||||
return normalizedAlgorithm switch
|
||||
{
|
||||
"sha256" => SHA256.TryHashData(data, destination, out bytesWritten),
|
||||
"sha384" => SHA384.TryHashData(data, destination, out bytesWritten),
|
||||
"sha512" => SHA512.TryHashData(data, destination, out bytesWritten),
|
||||
_ => throw new NotSupportedException($"Unsupported hash algorithm: {algorithm}")
|
||||
};
|
||||
}
|
||||
|
||||
public string FormatDigest(string algorithm, ReadOnlySpan<byte> digest)
|
||||
{
|
||||
var normalizedAlgorithm = algorithm.ToLowerInvariant().Replace("-", string.Empty);
|
||||
var hexDigest = Convert.ToHexString(digest).ToLowerInvariant();
|
||||
return $"{normalizedAlgorithm}:{hexDigest}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user