Crypto Provider Registry Contract
Contract ID: CONTRACT-CRYPTO-PROVIDER-REGISTRY-010 Version: 1.1 Status: Published Last Updated: 2026-05-30
Overview
This contract defines the ICryptoProviderRegistry interface for managing cryptographic providers across StellaOps modules. It supports pluggable crypto implementations including the in-process .NET default provider, FIPS 140-2/140-3, GOST (Russian), Chinese SM, and EU eIDAS algorithm families.
Audience: Module engineers resolving a hasher or signer through the registry, and crypto-plugin authors implementing a regional algorithm pack. Several sections call out members and endpoints that earlier revisions documented but that do not exist in src/ — treat those >-quoted notes as authoritative corrections.
StellaOps cryptography is organised into two cooperating layers, and this contract covers both:
- Registry / resolution layer (
src/__Libraries/StellaOps.Cryptography/) — theICryptoProvider/ICryptoProviderRegistrytypes that other modules consume to resolve a hasher or signer for a given capability and algorithm using deterministic provider ordering. - Plugin layer (
src/Cryptography/StellaOps.Cryptography.Plugin.*) — regional algorithm packs (FIPS, GOST, SM, eIDAS, HSM, OpenPGP) implemented onCryptoPluginBase/ICryptoCapability, loaded dynamically by the plugin loader.
The two layers use different abstractions (the registry layer is capability-oriented; the plugin layer is operation-oriented). Do not assume a single uniform interface across both.
Implementation References
- Registry & core types:
src/__Libraries/StellaOps.Cryptography/ICryptoProvider,ICryptoProviderRegistry,CryptoCapability,CryptoKeyReference,CryptoSignerResolution,CryptoHasherResolution,ICryptoHasher—CryptoProvider.csCryptoProviderRegistry(default implementation) —CryptoProviderRegistry.csDefaultCryptoProvider(Name = "default"),LibsodiumCryptoProvider(Name = "libsodium")ICryptoSigner—ICryptoSigner.cs- Metrics —
CryptoProviderMetrics.cs - Compliance profiles —
ComplianceProfiles.cs,CryptoComplianceOptions.cs
- DI registration:
src/__Libraries/StellaOps.Cryptography.DependencyInjection/CryptoServiceCollectionExtensions,CryptoPluginServiceCollectionExtensions,ServiceRegisteredCryptoProviderRegistry,CryptoPluginProviderRegistry,CryptoProviderRegistryOptions
- Plugin loader & config:
src/__Libraries/StellaOps.Cryptography.PluginLoader/(CryptoPluginConfiguration.cs) - Provider plugins:
src/Cryptography/StellaOps.Cryptography.Plugin.Fips/,…Plugin.Gost/,…Plugin.Sm/,…Plugin.Eidas/,…Plugin.Hsm/,…Plugin.OpenPgp/ - Plugin base & capability contract:
src/Cryptography/StellaOps.Cryptography.Plugin/CryptoPluginBase.cs;src/Plugin/StellaOps.Plugin.Abstractions/Capabilities/ICryptoCapability.cs
Note: Earlier revisions of this contract referenced
src/Security/StellaOps.Security.Crypto/andsrc/Security/StellaOps.Security.Crypto.Providers/. Those paths do not exist — the SPRINT_20260430_017 consolidation moved all canonical crypto types intosrc/__Libraries/StellaOps.Cryptography/.
Interface Definition (Registry / Resolution Layer)
ICryptoProviderRegistry
Source: src/__Libraries/StellaOps.Cryptography/CryptoProvider.cs
public interface ICryptoProviderRegistry
{
/// <summary>All registered providers (deterministic order).</summary>
IReadOnlyCollection<ICryptoProvider> Providers { get; }
/// <summary>Resolves a provider by name (case-insensitive).</summary>
bool TryResolve(string preferredProvider, out ICryptoProvider provider);
/// <summary>
/// Resolves the first provider that supports the capability/algorithm
/// (honours preferred-provider ordering); throws if none match.
/// </summary>
ICryptoProvider ResolveOrThrow(CryptoCapability capability, string algorithmId);
/// <summary>Resolves a signer for the algorithm and key reference.</summary>
CryptoSignerResolution ResolveSigner(
CryptoCapability capability,
string algorithmId,
CryptoKeyReference keyReference,
string? preferredProvider = null);
/// <summary>Resolves a content hasher for the algorithm.</summary>
CryptoHasherResolution ResolveHasher(string algorithmId, string? preferredProvider = null);
}
public sealed record CryptoSignerResolution(ICryptoSigner Signer, string ProviderName);
public sealed record CryptoHasherResolution(ICryptoHasher Hasher, string ProviderName);
There are no
RegisterProvider,GetProvider,GetDefaultProvider,ListProviders, orHasProvidermembers. Provider sets are supplied via DI (constructor injection ofIEnumerable<ICryptoProvider>); preferred ordering is configured throughCryptoProviderRegistryOptions. There is no mutable “default provider” concept — selection is by capability/algorithm support plus the configured preferred order.
ICryptoProvider
Source: src/__Libraries/StellaOps.Cryptography/CryptoProvider.cs
public interface ICryptoProvider
{
/// <summary>Provider name, e.g. "default", "libsodium".</summary>
string Name { get; }
/// <summary>Returns true if this provider can perform the capability with the algorithm.</summary>
bool Supports(CryptoCapability capability, string algorithmId);
IPasswordHasher GetPasswordHasher(string algorithmId);
/// <summary>Content hasher for the supplied algorithm (e.g., SHA-256).</summary>
ICryptoHasher GetHasher(string algorithmId);
/// <summary>Signer for the algorithm and registered key reference.</summary>
ICryptoSigner GetSigner(string algorithmId, CryptoKeyReference keyReference);
/// <summary>Verification-only signer built from raw public key bytes (SPKI/DER). Optional; default throws.</summary>
ICryptoSigner CreateEphemeralVerifier(string algorithmId, ReadOnlySpan<byte> publicKeyBytes);
void UpsertSigningKey(CryptoSigningKey signingKey);
bool RemoveSigningKey(string keyId);
IReadOnlyCollection<CryptoSigningKey> GetSigningKeys();
}
This is not the
ProviderId/DisplayName/SupportedAlgorithms/CreateHashAlgorithm/CreateSignatureAlgorithm/CreateKdfsurface that older revisions documented. Those members do not exist onICryptoProvider. The provider does not return BCLHashAlgorithm/AsymmetricAlgorithm/KeyDerivationPrfinstances; it returns the StellaOps abstractionsICryptoHasherandICryptoSigner.
CryptoCapability
Source: src/__Libraries/StellaOps.Cryptography/CryptoProvider.cs
public enum CryptoCapability
{
PasswordHashing,
Signing,
Verification,
SymmetricEncryption,
KeyDerivation,
ContentHashing
}
CryptoKeyReference
public sealed record CryptoKeyReference(string KeyId, string? ProviderHint = null);
ICryptoSigner
Source: src/__Libraries/StellaOps.Cryptography/ICryptoSigner.cs
public interface ICryptoSigner
{
string KeyId { get; }
string AlgorithmId { get; } // e.g., ES256
ValueTask<byte[]> SignAsync(ReadOnlyMemory<byte> data, CancellationToken ct = default);
ValueTask<bool> VerifyAsync(ReadOnlyMemory<byte> data, ReadOnlyMemory<byte> signature, CancellationToken ct = default);
JsonWebKey ExportPublicJsonWebKey(); // public components only
}
ICryptoHasher
Source: src/__Libraries/StellaOps.Cryptography/CryptoProvider.cs
public interface ICryptoHasher
{
string AlgorithmId { get; } // e.g., SHA-256, GOST-R-34.11-2012-256
byte[] ComputeHash(ReadOnlySpan<byte> data);
string ComputeHashHex(ReadOnlySpan<byte> data); // lowercase hex
}
Interface Definition (Plugin Layer)
Regional algorithm packs are implemented on CryptoPluginBase, which implements both IPlugin and ICryptoCapability. This is an operation-oriented contract (not the capability/algorithm resolution model of the registry layer).
Source: src/Plugin/StellaOps.Plugin.Abstractions/Capabilities/ICryptoCapability.cs, src/Cryptography/StellaOps.Cryptography.Plugin/CryptoPluginBase.cs
public interface ICryptoCapability
{
IReadOnlyList<string> SupportedAlgorithms { get; }
bool CanHandle(CryptoOperation operation, string algorithm);
Task<byte[]> SignAsync(ReadOnlyMemory<byte> data, CryptoSignOptions options, CancellationToken ct);
Task<bool> VerifyAsync(ReadOnlyMemory<byte> data, ReadOnlyMemory<byte> signature, CryptoVerifyOptions options, CancellationToken ct);
Task<byte[]> EncryptAsync(ReadOnlyMemory<byte> data, CryptoEncryptOptions options, CancellationToken ct);
Task<byte[]> DecryptAsync(ReadOnlyMemory<byte> data, CryptoDecryptOptions options, CancellationToken ct);
Task<byte[]> HashAsync(ReadOnlyMemory<byte> data, string algorithm, CancellationToken ct);
}
public enum CryptoOperation { Sign, Verify, Encrypt, Decrypt, Hash }
Each plugin advertises a PluginInfo record (CryptoPluginBase.Info) with Id, Name, Version, Vendor, Description, LicenseId. There is no provider_id / display_name / compliance / is_default JSON DTO emitted by the runtime — plugin metadata is carried by PluginInfo and the on-disk plugin.yaml manifest.
Plugin metadata example (plugin.yaml)
Source: src/Cryptography/StellaOps.Cryptography.Plugin.Fips/plugin.yaml
plugin:
id: com.stellaops.crypto.fips
name: FIPS 140-2 Cryptography Provider
version: 1.0.0
vendor: Stella Ops
description: US FIPS 140-2 compliant cryptographic algorithms
license: BUSL-1.1
entryPoint: StellaOps.Cryptography.Plugin.Fips.FipsPlugin
minPlatformVersion: 1.0.0
capabilities:
- type: crypto
id: fips
algorithms: [ RSA-SHA256, ECDSA-P256-SHA256, AES-256-GCM, SHA-256, HMAC-SHA256, ... ]
Available Providers
Default Provider (registry layer)
Source: src/__Libraries/StellaOps.Cryptography/DefaultCryptoProvider.cs
| Provider Name | default |
|---|---|
| Signing | ES256 only |
| Content hashing | SHA-256, SHA-384, SHA-512 |
| Password hashing | Argon2id, PBKDF2 (Pbkdf2-SHA256) |
| Compliance | None (platform default) |
The default provider does not advertise general RSA/ECDSA/EdDSA signing. EdDSA (Ed25519) is provided by the separate
LibsodiumCryptoProvider(Name = "libsodium") and the BouncyCastle Ed25519 provider; broader RSA/ECDSA families are provided by the FIPS plugin (see below).
FIPS Provider (plugin layer)
Source: src/Cryptography/StellaOps.Cryptography.Plugin.Fips/FipsPlugin.cs
| Plugin Id | com.stellaops.crypto.fips |
|---|---|
| Plugin Name | FIPS 140-2 Cryptography Provider |
| Algorithms | RSA-SHA256/384/512, RSA-PSS-SHA256/384/512, ECDSA-P256-SHA256, ECDSA-P384-SHA384, ECDSA-P521-SHA512, AES-128/256-CBC, AES-128/256-GCM, SHA-256/384/512, HMAC-SHA256/384/512 |
| Compliance | FIPS 140-2 / 140-3 (compliance profile fips) |
| Notes | RequireFipsMode verifies OS-level FIPS via IFipsModeProbe (Windows registry / Linux /proc/sys/crypto/fips_enabled). |
GOST Provider (plugin layer)
Source: src/Cryptography/StellaOps.Cryptography.Plugin.Gost/GostPlugin.cs
| Plugin Id | com.stellaops.crypto.gost |
|---|---|
| Plugin Name | GOST Cryptography Provider |
| Algorithms | GOST-R34.10-2012-256 (sign/verify), GOST-R34.11-2012-256, GOST-R34.11-2012-512 (hash), GOST-28147-89, GOST-GCM (symmetric) |
| Compliance | GOST (compliance profile gost) |
| Notes | BouncyCastle software harness. Generated keys are limited to GOST-R34.10-2012-256; production GOST signing requires a CryptoPro/OpenSSL-GOST/PKCS#11 adapter. GOST-GCM is internally substituted with GOST-28147-89 CBC (no certified software AEAD). |
SM Provider (plugin layer, China)
Source: src/Cryptography/StellaOps.Cryptography.Plugin.Sm/SmPlugin.cs
| Plugin Id | com.stellaops.crypto.sm |
|---|---|
| Plugin Name | Chinese SM Cryptography Provider |
| Algorithms | SM2-SM3, SM2-SHA256 (sign/verify), SM3 (hash), SM4-CBC, SM4-ECB, SM4-GCM (symmetric) |
| Compliance | GM/T 0003-0004 (compliance profile sm) |
eIDAS Provider (plugin layer, EU)
Source: src/Cryptography/StellaOps.Cryptography.Plugin.Eidas/EidasPlugin.cs
| Plugin Id | com.stellaops.crypto.eidas |
|---|---|
| Plugin Name | eIDAS Cryptography Provider |
| Algorithms | eIDAS-RSA-SHA256/384/512, eIDAS-ECDSA-SHA256/384, eIDAS-CAdES-BES/T/LT/LTA, eIDAS-XAdES-BES |
| Compliance | EU eIDAS / ETSI TS 119 312 (compliance profile eidas) |
Additional plugin packs exist in the same directory:
StellaOps.Cryptography.Plugin.HsmandStellaOps.Cryptography.Plugin.OpenPgp. AStellaOps.Cryptography.Plugin.CryptoProreference is gated behind theStellaOpsEnableCryptoProMSBuild property but the project is not present in this repository tree (proprietary CryptoPro CSP pack).
Configuration
Registration at Startup
Source: src/__Libraries/StellaOps.Cryptography.DependencyInjection/CryptoPluginServiceCollectionExtensions.cs, CryptoServiceCollectionExtensions.PluginConfiguration.cs, CryptoServiceCollectionExtensions.Registry.cs
The recommended production registration is configuration-driven plugin loading:
// Bind StellaOps:Crypto:Plugins and StellaOps:Crypto:Compliance from IConfiguration,
// and register ICryptoProviderRegistry (CryptoPluginProviderRegistry).
services.AddStellaOpsCryptoWithPlugins(configuration, options =>
{
// optional CryptoPluginConfiguration tweaks
});
// Or, with an explicit compliance profile:
services.AddStellaOpsCryptoFromConfiguration(
configuration,
complianceProfileId: "fips", // "world" | "fips" | "gost" | "sm" | "kcmvp" | "eidas"
strictValidation: true);
When no plugin loader is wired, the base registration registers ServiceRegisteredCryptoProviderRegistry as the ICryptoProviderRegistry singleton over the DI-registered ICryptoProvider instances.
There is no
AddCryptoProviderRegistry(options => …)API and nooptions.RegisterProvider<T>("id")/options.DefaultProvider = …builder. Providers come from DI; preferred ordering is set viaCryptoProviderRegistryOptions(PreferredProviders,ActiveProfile, per-profileProfiles).
Plugin loader configuration
Source: src/__Libraries/StellaOps.Cryptography.PluginLoader/CryptoPluginConfiguration.cs — bound from configuration section StellaOps:Crypto:Plugins.
| Key | Default | Description |
|---|---|---|
ManifestPath | /etc/stellaops/crypto-plugins-manifest.json | Plugin manifest path |
DiscoveryMode | explicit | explicit (only configured plugins) or auto |
Enabled[] | [] | Enabled plugins (Id, optional Priority, Options) |
Disabled[] | [] | Plugin IDs/patterns to disable |
FailOnMissingPlugin | true | Fail startup if a configured plugin is missing |
RequireAtLeastOne | true | Require at least one provider to load |
Compliance | — | CryptoComplianceConfiguration (ProfileId, StrictValidation, EnforceJurisdiction, AllowedJurisdictions[]) |
Provider Selection
var registry = serviceProvider.GetRequiredService<ICryptoProviderRegistry>();
// All registered providers
var providers = registry.Providers;
// Resolve a provider by name (case-insensitive)
if (registry.TryResolve("default", out var provider)) { /* … */ }
// Resolve by capability + algorithm (honours preferred order)
var hashProvider = registry.ResolveOrThrow(CryptoCapability.ContentHashing, "SHA-256");
API Endpoints
NOT IMPLEMENTED (forward design only). No HTTP API for the crypto provider registry exists in the codebase. There are no
GET /api/v1/crypto/providers,GET /api/v1/crypto/providers/{id}, orPUT /api/v1/crypto/providers/defaultroutes (no controller or minimal-API mapping matchescrypto/providers), and there is no associated Authority scope. The registry is consumed in-process via dependency injection only; provider/profile selection is configuration-driven (see Configuration). The sketch below is retained as a proposed future surface and must not be treated as an available API.
# PROPOSED (not implemented)
GET /api/v1/crypto/providers
GET /api/v1/crypto/providers/{provider_id}
PUT /api/v1/crypto/providers/default
Algorithm Mapping
Algorithm identifiers below are the actual tokens advertised by each provider/plugin (verified against SupportedAlgorithms / plugin.yaml). They are not normalised across families — callers pass the exact token.
Hash Algorithms
| Algorithm token | default | FIPS plugin | GOST plugin | SM plugin |
|---|---|---|---|---|
SHA-256 / SHA-384 / SHA-512 | Yes | Yes | No | No |
GOST-R34.11-2012-256 | No | No | Yes | No |
GOST-R34.11-2012-512 | No | No | Yes | No |
SM3 | No | No | No | Yes |
Signature Algorithms
| Algorithm token | default | FIPS plugin | GOST plugin | SM plugin |
|---|---|---|---|---|
ES256 | Yes | No (uses ECDSA-P256-SHA256) | No | No |
RSA-PSS-SHA256/384/512 | No | Yes | No | No |
ECDSA-P256-SHA256 / ECDSA-P384-SHA384 / ECDSA-P521-SHA512 | No | Yes | No | No |
RSA-SHA256/384/512 | No | Yes | No | No |
GOST-R34.10-2012-256 | No | No | Yes | No |
SM2-SM3 / SM2-SHA256 | No | No | No | Yes |
EdDSA (Ed25519) is not handled by the providers above; it is served by the
libsodium/BouncyCastle Ed25519 registry-layer providers.
Usage Example
Resolving a hasher (registry layer)
var registry = services.GetRequiredService<ICryptoProviderRegistry>();
var resolution = registry.ResolveHasher("SHA-256");
var digestHex = resolution.Hasher.ComputeHashHex(data); // resolution.ProviderName = "default"
Hashing with SM3 (plugin layer)
// SmPlugin implements ICryptoCapability; resolve the plugin and call HashAsync.
var digest = await smPlugin.HashAsync(data, "SM3", ct);
Signing with GOST (plugin layer)
// GostPlugin signs with GOST-R34.10-2012-256 (GOST R 34.11-2012 digest).
var signature = await gostPlugin.SignAsync(
data,
new CryptoSignOptions(Algorithm: "GOST-R34.10-2012-256", KeyId: keyId),
ct);
Metrics
Source: src/__Libraries/StellaOps.Cryptography/CryptoProviderMetrics.cs
| Meter | stellaops.crypto (version 1.0.0) |
|---|---|
crypto_provider_resolutions_total | Counter; successful provider resolutions. Tags: provider, capability, algorithm. |
crypto_provider_resolution_failures_total | Counter; failed resolutions. Tags: capability, algorithm. |
Environment Variables
Source: src/__Libraries/StellaOps.Cryptography/CryptoComplianceOptions.cs (ApplyEnvironmentOverrides)
| Variable | Description |
|---|---|
STELLAOPS_CRYPTO_COMPLIANCE_PROFILE | Overrides the active compliance profile ID (world, fips, gost, sm, kcmvp, eidas). |
STELLAOPS_CRYPTO_STRICT_VALIDATION | true/false — overrides strict compliance validation. |
The following variables documented in earlier revisions are not runtime environment variables and do not exist as such in the codebase:
STELLAOPS_CRYPTO_DEFAULT_PROVIDER,StellaOpsEnableSmCrypto,STELLAOPS_FIPS_MODE.StellaOpsEnableCryptoProis an MSBuild build-time property (a<ProjectReference>condition inStellaOps.Cryptography.DependencyInjection.csproj), not a runtime toggle. FIPS-mode enforcement is driven by the FIPS pluginRequireFipsModeoption probing the OS, not by an environment variable.
Compliance Profiles
Source: src/__Libraries/StellaOps.Cryptography/ComplianceProfiles.cs, CryptoComplianceOptions.cs
Valid profile IDs: world (default), fips, gost, sm, kcmvp, eidas. Each profile maps hash/HMAC purposes (Graph, Symbol, Content, Merkle, Attestation, Interop, Secret) to concrete algorithms (e.g. world uses BLAKE3 for graph content-addressing and SHA-256 elsewhere; fips uses SHA-256 throughout and PBKDF2 for secrets).
Related Contracts
- Verification Policy Contract - Algorithm selection
- Sealed Mode Contract - Offline crypto validation
