- Added DefaultCryptoHmac class implementing ICryptoHmac interface. - Introduced purpose-based HMAC computation methods. - Implemented verification methods for HMACs with constant-time comparison. - Created HmacAlgorithms and HmacPurpose classes for well-known identifiers. - Added compliance profile support for HMAC algorithms. - Included asynchronous methods for HMAC computation from streams.
201 lines
7.4 KiB
C#
201 lines
7.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Options;
|
|
using StellaOps.Cryptography;
|
|
#if STELLAOPS_CRYPTO_PRO
|
|
using StellaOps.Cryptography.Plugin.CryptoPro;
|
|
#endif
|
|
using StellaOps.Cryptography.Plugin.Pkcs11Gost;
|
|
using StellaOps.Cryptography.Plugin.OpenSslGost;
|
|
|
|
namespace StellaOps.Cryptography.DependencyInjection;
|
|
|
|
/// <summary>
|
|
/// Dependency injection helpers for registering StellaOps cryptography services.
|
|
/// </summary>
|
|
public static class CryptoServiceCollectionExtensions
|
|
{
|
|
/// <summary>
|
|
/// Registers the default crypto provider and registry.
|
|
/// </summary>
|
|
/// <param name="services">Service collection.</param>
|
|
/// <param name="configureRegistry">Optional registry ordering configuration.</param>
|
|
/// <param name="configureProvider">Optional provider-level configuration (e.g. key registration).</param>
|
|
/// <returns>The service collection.</returns>
|
|
public static IServiceCollection AddStellaOpsCrypto(
|
|
this IServiceCollection services,
|
|
Action<CryptoProviderRegistryOptions>? configureRegistry = null,
|
|
Action<DefaultCryptoProvider>? configureProvider = null)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(services);
|
|
|
|
if (configureRegistry is not null)
|
|
{
|
|
services.Configure(configureRegistry);
|
|
}
|
|
|
|
// Register compliance options with default profile
|
|
services.TryAddSingleton<IOptionsMonitor<CryptoComplianceOptions>>(sp =>
|
|
{
|
|
var configuration = sp.GetService<IConfiguration>();
|
|
var options = new CryptoComplianceOptions();
|
|
configuration?.GetSection(CryptoComplianceOptions.SectionKey).Bind(options);
|
|
options.ApplyEnvironmentOverrides();
|
|
return new StaticComplianceOptionsMonitor(options);
|
|
});
|
|
|
|
// Register compliance service
|
|
services.TryAddSingleton<ICryptoComplianceService, CryptoComplianceService>();
|
|
|
|
services.TryAddSingleton<DefaultCryptoProvider>(sp =>
|
|
{
|
|
var provider = new DefaultCryptoProvider();
|
|
configureProvider?.Invoke(provider);
|
|
return provider;
|
|
});
|
|
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<ICryptoProvider, DefaultCryptoProvider>());
|
|
|
|
#if STELLAOPS_CRYPTO_SODIUM
|
|
services.TryAddSingleton<LibsodiumCryptoProvider>();
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<ICryptoProvider, LibsodiumCryptoProvider>());
|
|
#endif
|
|
|
|
services.TryAddSingleton<ICryptoHash, DefaultCryptoHash>();
|
|
services.TryAddSingleton<ICryptoHmac, DefaultCryptoHmac>();
|
|
|
|
services.TryAddSingleton<ICryptoProviderRegistry>(sp =>
|
|
{
|
|
var providers = sp.GetServices<ICryptoProvider>();
|
|
var options = sp.GetService<IOptionsMonitor<CryptoProviderRegistryOptions>>();
|
|
IEnumerable<string>? preferred = options?.CurrentValue?.ResolvePreferredProviders();
|
|
return new CryptoProviderRegistry(providers, preferred);
|
|
});
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers crypto services with compliance profile configuration.
|
|
/// </summary>
|
|
/// <param name="services">Service collection.</param>
|
|
/// <param name="configuration">Configuration root.</param>
|
|
/// <param name="configureCompliance">Optional compliance configuration.</param>
|
|
/// <returns>The service collection.</returns>
|
|
public static IServiceCollection AddStellaOpsCryptoWithCompliance(
|
|
this IServiceCollection services,
|
|
IConfiguration configuration,
|
|
Action<CryptoComplianceOptions>? configureCompliance = null)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(services);
|
|
ArgumentNullException.ThrowIfNull(configuration);
|
|
|
|
// Bind compliance options from configuration
|
|
services.Configure<CryptoComplianceOptions>(options =>
|
|
{
|
|
configuration.GetSection(CryptoComplianceOptions.SectionKey).Bind(options);
|
|
configureCompliance?.Invoke(options);
|
|
options.ApplyEnvironmentOverrides();
|
|
});
|
|
|
|
// Register compliance service with options monitor
|
|
services.TryAddSingleton<ICryptoComplianceService, CryptoComplianceService>();
|
|
|
|
// Register base crypto services
|
|
services.AddStellaOpsCrypto();
|
|
|
|
return services;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper class for static options monitoring.
|
|
/// </summary>
|
|
private sealed class StaticComplianceOptionsMonitor : IOptionsMonitor<CryptoComplianceOptions>
|
|
{
|
|
private readonly CryptoComplianceOptions _options;
|
|
|
|
public StaticComplianceOptionsMonitor(CryptoComplianceOptions options)
|
|
=> _options = options;
|
|
|
|
public CryptoComplianceOptions CurrentValue => _options;
|
|
|
|
public CryptoComplianceOptions Get(string? name) => _options;
|
|
|
|
public IDisposable OnChange(Action<CryptoComplianceOptions, string> listener)
|
|
=> NullDisposable.Instance;
|
|
|
|
private sealed class NullDisposable : IDisposable
|
|
{
|
|
public static readonly NullDisposable Instance = new();
|
|
public void Dispose() { }
|
|
}
|
|
}
|
|
|
|
public static IServiceCollection AddStellaOpsCryptoRu(
|
|
this IServiceCollection services,
|
|
IConfiguration configuration,
|
|
Action<CryptoProviderRegistryOptions>? configureRegistry = null)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(services);
|
|
ArgumentNullException.ThrowIfNull(configuration);
|
|
|
|
var baseSection = configuration.GetSection("StellaOps:Crypto");
|
|
services.Configure<StellaOpsCryptoOptions>(baseSection);
|
|
services.Configure<CryptoProviderRegistryOptions>(baseSection.GetSection("Registry"));
|
|
#if STELLAOPS_CRYPTO_PRO
|
|
services.Configure<CryptoProGostProviderOptions>(baseSection.GetSection("CryptoPro"));
|
|
#endif
|
|
services.Configure<Pkcs11GostProviderOptions>(baseSection.GetSection("Pkcs11"));
|
|
services.Configure<OpenSslGostProviderOptions>(baseSection.GetSection("OpenSsl"));
|
|
|
|
services.AddStellaOpsCrypto(configureRegistry);
|
|
services.AddOpenSslGostProvider();
|
|
services.AddPkcs11GostProvider();
|
|
#if STELLAOPS_CRYPTO_PRO
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
services.AddCryptoProGostProvider();
|
|
}
|
|
#endif
|
|
|
|
services.PostConfigure<CryptoProviderRegistryOptions>(options =>
|
|
{
|
|
EnsurePreferred(options.PreferredProviders);
|
|
foreach (var profile in options.Profiles.Values)
|
|
{
|
|
EnsurePreferred(profile.PreferredProviders);
|
|
}
|
|
});
|
|
|
|
return services;
|
|
|
|
static void EnsurePreferred(IList<string> providers)
|
|
{
|
|
InsertIfMissing(providers, "ru.pkcs11");
|
|
InsertIfMissing(providers, "ru.openssl.gost");
|
|
#if STELLAOPS_CRYPTO_PRO
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
InsertIfMissing(providers, "ru.cryptopro.csp");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void InsertIfMissing(IList<string> providers, string name)
|
|
{
|
|
for (var i = 0; i < providers.Count; i++)
|
|
{
|
|
if (string.Equals(providers[i], name, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
providers.Insert(0, name);
|
|
}
|
|
}
|
|
}
|