SAIF.NetCore.SystemHash architecture¶
SAIF.NetCore.SystemHash is a single-class implementation-layer library in the Framework.NCore dependency graph that adapts SAIF.NetCore.HashUtil's reversible salting primitive into a caller-identity credential scheme used by the Environment API and OIDC crypto settings; it is one of the three documented implementation-to-implementation exceptions in Architecture.md because it takes a direct NuGet package dependency on SAIF.NetCore.HashUtil in addition to the foundation package SAIF.NetCore.ServiceContracts.
Responsibilities¶
- Implement
ISystemHashService(SAIF.NetCore.ServiceContracts) as the repository's sole concreteSystemHashService, producing a SHA-256/Base64 identity hash from aSystemTypeand system name. - Issue a salted, time-stamped credential (
ComputeHash,Get) by delegating the salting mechanics toSAIF.NetCore.HashUtil'sSaltShakerwhile supplying the embedded create timestamp itself. - Compute the unsalted identity hash on demand (
ComputeHashNow) and de-salt plus validate the lifetime of a previously issued hash (RemoveSystemHashSaltAndValidateLifetime), throwingSystemHashExpiredExceptionwhen expired. - Resolve the identity assembly used to build the hash (
GetAssembly), defaulting toAssembly.GetCallingAssembly()unless an assembly was supplied to the constructor.
Component boundaries¶
SystemHashService: the only public type in the library; it owns the SHA-256/Base64 computation, the choice ofDateTime.Nowas the embedded create date, assembly-name resolution, and the lifetime/expiry decision.- Boundary with
SAIF.NetCore.HashUtil:SystemHashServiceconstructsSaltShakerdirectly (once with aDateTimeto salt, once parameterless to de-salt) and constructs/throwsSystemHashExpiredException; HashUtil owns only the salting/de-salting mechanics and never compares dates itself. - Boundary with
SAIF.NetCore.ServiceContracts: the library implementsISystemHashServiceand consumes theSystemTypeenum as its sole input type; it has no other contract dependency. - Boundary with consumers:
SAIF.NetCore.ServiceExtensionsconstructsSystemHashService(Assembly)and registers it as a singleton factory forISystemHashService(used byRegisterSecureEnvironmentClientand inline byRegisterDBConnectionClient);SAIF.NetCore.EnvironmentClientandSAIF.NetCore.OIDCconsume only theISystemHashServiceinterface, with no package reference to SystemHash itself.
Interaction model¶
- Client-side credential issuance: a consumer calls
Get(systemType)orComputeHash(systemType, systemName);SystemHashServicecomputes the SHA-256/Base64 hash, constructsSaltShaker(DateTime.Now), and callsSaltHashto produce the salted 120-character credential string. - Server-side validation: a consumer calls
RemoveSystemHashSaltAndValidateLifetime(systemHashValue, expireSeconds, nowBufferSeconds);SystemHashServiceconstructs a parameterlessSaltShaker, callsBlandHashto recover the original hash and create date, compares the recovered date against the supplied lifetime, and either returns the de-salted value or throwsSystemHashExpiredException. - There is no inbound or outbound network call anywhere in this library; both operations are in-process cryptographic/string computation backed by
HashUtil. ISystemHashServiceis reached bySAIF.NetCore.EnvironmentClientandSAIF.NetCore.OIDCpurely through theSAIF.NetCore.ServiceContractsinterface — neither library takes a package reference toSAIF.NetCore.SystemHash— so the only architectural NuGet edges into this library are fromSAIF.NetCore.ServiceExtensions.
Architecture diagram¶
The following diagram shows SystemHash's position relative to its one implementation-layer exception dependency, the foundation layer, and the rest of the Framework.NCore dependency graph.
flowchart TB
SC["SAIF.NetCore.ServiceContracts<br>(ISystemHashService, SystemType)"]
HASH["SAIF.NetCore.HashUtil<br>(SaltShaker, SystemHashExpiredException)"]
SYSHASH["SAIF.NetCore.SystemHash<br>(SystemHashService)"]
SE["SAIF.NetCore.ServiceExtensions"]
ENVCLIENT["SAIF.NetCore.EnvironmentClient<br>(ISystemHashService consumer, interface-only)"]
OIDC["SAIF.NetCore.OIDC<br>(ISystemHashService consumer, interface-only)"]
APP["Consuming application"]
SYSHASH -.->|NuGet ref| SC
SYSHASH -.->|NuGet ref: documented exception| HASH
SE -.->|NuGet ref| SYSHASH
ENVCLIENT -.->|interface only, no package ref| SC
OIDC -.->|interface only, no package ref| SC
APP -.->|NuGet ref| SE
Sequence diagram¶
The following diagram shows the primary salted-credential issue and validate round trip.
sequenceDiagram
participant Caller
participant SystemHashService
participant SaltShaker
Caller->>SystemHashService: Get(systemType)
SystemHashService->>SystemHashService: GetAssembly() + SHA-256/Base64 hash
SystemHashService->>SaltShaker: new SaltShaker(DateTime.Now)
SystemHashService->>SaltShaker: SaltHash(systemHash)
SaltShaker-->>SystemHashService: salted hash string
SystemHashService-->>Caller: salted hash string
Caller->>SystemHashService: RemoveSystemHashSaltAndValidateLifetime(saltedHash, expireSeconds, nowBufferSeconds)
SystemHashService->>SaltShaker: new SaltShaker()
SystemHashService->>SaltShaker: BlandHash(saltedHash, out createDate)
SaltShaker-->>SystemHashService: original hash + createDate
SystemHashService->>SystemHashService: Compare createDate against lifetime
SystemHashService-->>Caller: value, or throw SystemHashExpiredException
Design constraints¶
Get(type)recomputes and re-salts on every call rather than caching, so each call normally returns a different string — though this is not guaranteed, since calls within the same millisecond share a timestamp and the randomized insertion choices can repeat — contradicting the class and interface XML-doc wording that implies caching*.GetAssembly()returnsAssembly.GetCallingAssembly(), notAssembly.GetEntryAssembly()as its doc comment states; with the parameterless constructor this most likely resolves to theSAIF.NetCore.SystemHashassembly itself rather than the consuming application, making the identity non-unique per application unless the caller supplies an assembly explicitly*.- No in-repo production code calls
ComputeHashNoworRemoveSystemHashSaltAndValidateLifetime; both are intended for the external validating service (the Environment API's "GetSystemHash route")*. - Lifetime validation uses host-local
DateTime.Nowfor both the embedded create date and the validation clock, so issuer and validator must share the same local time zone and a culture that round-trips HashUtil's date format for expiry checks to be correct*. SAIF.NetCore.ServiceExtensions'sRegisterEnvironmentClient(non-secure path) registersISystemHashServicevia a factory that returnsnull, so anySystemTypesecure-setting overload invoked in a non-secure startup throws aNullReferenceException*.
Related documentation¶
- Index
- Overview
- Dependencies
- Operations and processes
- Business rules
- Security and authorization
- API reference
- SAIF.NetCore.HashUtil overview
- SAIF.NetCore.ServiceContracts overview
Note: Statements marked with
*were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.
Sources¶
src/SAIF.NetCore.SystemHash/SAIF.NetCore.SystemHash/SAIF.NetCore.SystemHash/SAIF.NetCore.SystemHash.csprojsrc/SAIF.NetCore.SystemHash/SAIF.NetCore.SystemHash/SAIF.NetCore.SystemHash/SystemHashService.cssrc/SAIF.NetCore.HashUtil/SAIF.NetCore.HashUtil/SaltShaker.cs,SystemHashExpiredException.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cssrc/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/OidcSettings.csArchitecture.md