Release Notes — Cryptography IHmacAlgorithm primitive
Sprint: SPRINT_20260430_000_Cryptography_hmac_primitive Module: Cryptography (src/Cryptography/)
20260430-017 follow-up — assembly unified, collision retired
The primitive originally shipped in a parallel project at src/Cryptography/StellaOps.Cryptography/. That project’s default AssemblyName collided with the legacy src/__Libraries/StellaOps.Cryptography/ (both produced StellaOps.Cryptography.dll), so any service whose dependency graph reached both projects ended up with one DLL on disk and the legacy StellaOps.Cryptography.Audit.IAuthEventSink type silently dropped — breaking Auth.ServerIntegration at runtime. SPRINT_20260430_005 papered over the collision with <AssemblyName>StellaOps.Cryptography.Primitives</AssemblyName> as a stop-gap.
SPRINT_20260430_017 retires the collision. All types from src/Cryptography/StellaOps.Cryptography/ (HMAC primitives, plus pre-existing IContentSigner, IContentVerifier, MultiProfileSigner, SignatureProfile, Models/*, KeyEscrow/*) plus DefaultHmacAlgorithm and FipsHmacAlgorithm moved into the canonical legacy assembly at src/__Libraries/StellaOps.Cryptography/. The duplicate-name csproj was deleted. Public namespaces are unchanged (StellaOps.Cryptography, StellaOps.Cryptography.Plugin, StellaOps.Cryptography.Plugin.Fips); consumer source code did not change. The SPRINT_005 Primitives rename was reverted (the renamed csproj is gone). Single StellaOps.Cryptography.dll is produced from the canonical project again. The conformance test allowlist was updated to reflect the new file locations and (unrelated to this sprint’s scope) absorbed 9 pre-existing legacy callsites with explicit follow-up task IDs (HMAC-CLEANUP-CLI-01, HMAC-CLEANUP-EXPORT-01…02, HMAC-CLEANUP-NOTIFY-01…04).
Summary
Introduces a top-level HMAC primitive — StellaOps.Cryptography.IHmacAlgorithm — in the core cryptography library. The primitive is required so that all HMAC operations across the StellaOps repository route through the regional crypto-plugin substitution pipeline (FIPS / GOST / SM / eIDAS), instead of calling System.Security.Cryptography.HMAC* directly.
Without this primitive, the downstream sprints SPRINT_20260430_001_Policy_registry_webhook_signature_validation and SPRINT_20260430_005_Notify_external_webhook_signature_validation would have to call BCL HMAC types directly, bypassing the regional plugin substitution that FIPS / GOST / SM installs depend on.
New public surface
StellaOps.Cryptography.IHmacAlgorithm— interface contract for MAC computation and constant-time verification.StellaOps.Cryptography.HmacAlgorithmName— value type identifying the HMAC algorithm. Static members:HmacSha256(default),HmacSha384,HmacSha512. The underlying tokens (HMAC-SHA256,HMAC-SHA384,HMAC-SHA512) match the names already advertised byFipsPlugin.SupportedAlgorithms.StellaOps.Cryptography.Plugin.DefaultHmacAlgorithm— default implementation, backed byHMACSHA256.HashData/HMACSHA384.HashData/HMACSHA512.HashDataandCryptographicOperations.FixedTimeEqualsfor constant-time verification.StellaOps.Cryptography.Plugin.Fips.FipsHmacAlgorithm— FIPS-bound implementation. Lifted from the inline HMAC switch previously embedded inFipsPlugin.HashAsync.
Behaviour
default(HmacAlgorithmName)resolves toHmacSha256. Callers omitting the algorithm parameter receive HMAC-SHA256.Verify(...)returnsfalsefor length-mismatched MACs without throwing.- Unknown algorithm names raise
ArgumentOutOfRangeExceptionfromHmacAlgorithmName.FromString,IHmacAlgorithm.ComputeMac, andIHmacAlgorithm.Verify. - Empty key and empty data are valid inputs (RFC 2104 does not restrict either).
Backwards-compatibility
- The legacy
FipsPlugin.HashAsync(data, "HMAC-SHA256"|"HMAC-SHA384"|"HMAC-SHA512", ct)call site continues to requireFipsOptions.HmacKeyBase64. The throw-on-missing-key contract is unchanged. The implementation now delegates toFipsHmacAlgorithm.ComputeMac(key, data, algorithm), but the configuration gate (GetRequiredHmacKey) still runs first. Existing tests (FipsPlugin_HmacWithoutConfiguredKey_FailsClosed) continue to pass. - No breaking changes to
IContentSigner,IContentVerifier,MultiProfileSigner, or any signature-profile contracts. - No new package dependencies.
Architecture-conformance enforcement
A new conformance test (CRYPTO-HMAC-05) — see src/Cryptography/__Tests/StellaOps.Cryptography.Tests/HmacBclCallSiteConformanceTests.cs — scans src/** for \bHMACSHA(256|384|512)\b references and fails the build if any file outside the crypto-plugin allow-list contains a direct BCL HMAC call.
The allow-list currently contains:
src/Cryptography/StellaOps.Cryptography.Plugin/DefaultHmacAlgorithm.cssrc/Cryptography/StellaOps.Cryptography.Plugin.Fips/FipsHmacAlgorithm.cssrc/Cryptography/StellaOps.Cryptography.Plugin.Fips/FipsPlugin.cs(the legacyFipsOptions.HmacKeyBase64-keyedHashAsyncpath; removed once callers migrate away)
Existing call sites that pre-date the conformance test are tracked in the allow-list as legacy entries; the conformance test treats them as already known and a follow-up cleanup sprint will migrate them to IHmacAlgorithm.
Test evidence
dotnet test src/Cryptography/__Tests/StellaOps.Cryptography.Tests/StellaOps.Cryptography.Tests.csproj -- --filter-class StellaOps.Cryptography.Tests.DefaultHmacAlgorithmTests→ Passed: 19, Failed: 0.dotnet test src/Cryptography/__Tests/StellaOps.Cryptography.Tests/StellaOps.Cryptography.Tests.csproj -- --filter-class StellaOps.Cryptography.Tests.FipsHmacAlgorithmTests→ Passed: 13, Failed: 0.- RFC 4231 test cases 1–5 and 7 are asserted for HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 across both the default and FIPS implementations.
