up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-27 23:44:42 +02:00
parent ef6e4b2067
commit 3b96b2e3ea
298 changed files with 47516 additions and 1168 deletions

View File

@@ -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}";
}
}