---
title: Generate a system hash
summary: Build a SHA-256-based system identifier and optionally salt it.
status: draft
owner: SAIF Framework
last_reviewed: 2026-07-30
library: SAIF.Framework.Security.EnvironmentApi
reference_type: package
operation_id: OP-ENV-011
trigger: Caller requests a system hash for secure-setting workflows
---

# Generate a system hash

This operation produces the identifier that callers present when requesting a secure configuration setting. It resolves the most plausible calling assembly name, hashes the resulting `{systemName}-{systemType}` payload with SHA-256, and — unless the caller explicitly asks for the raw value — wraps the digest with a time-based salt so its age can later be validated.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-ENV-011 |
| **Trigger** | Caller needs a system hash |
| **Inputs** | `SystemType`, optional explicit `systemName` |
| **Outputs** | Salted hash string from `ComputeHash` or `Get`, or unsalted hash string from `ComputeHashNow` |
| **Primary components** | `SystemHashUtil.Get`, `SystemHashUtil.GetAssembly`, `SystemHashUtil.ComputeHash`, `SystemHashUtil.ComputeHashNow`, `SystemHashUtil.GetHashValue` |
| **Entry point** | `SAIF.Framework.Security.EnvironmentApi\Services.Common\SystemHashUtil.cs` |

## Steps

1. Resolve the source system name when the caller did not supply one explicitly.
   - `Get(SystemType)` calls `GetAssembly()` and uses whichever assembly name that method returns.
   - `GetAssembly()` tries `Assembly.GetEntryAssembly()` first, then `GetWebEntryAssembly()`, then `GetLegacyWebEntryAssembly()`, and falls back to `Assembly.GetExecutingAssembly()` only if every prior candidate is unavailable.
2. Build the deterministic hash payload as `{systemName}-{(int)type}`, so the same system and type combination always produces the same input to the hash function.
3. Encode that payload as Unicode bytes, hash it with SHA-256, and convert the digest to Base64.
4. If the caller used `ComputeHash` or `Get`, pass the Base64 payload to `new SaltShaker(DateTime.Now).SaltHash(value)` and return the salted token.
5. If the caller used `ComputeHashNow`, skip salting entirely and return the direct Base64 hash for scenarios that need an immediate, unsalted value.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Caller requests system hash]) --> Name[Resolve system name or assembly]
	Name --> Payload[Build systemName-type payload]
	Payload --> Digest[SHA-256 hash and Base64 encode]
	Digest --> Salt{Salt result?}
	Salt -->|Yes| SaltHash[SaltHash with current timestamp]
	Salt -->|No| Raw([Return unsalted hash])
	SaltHash --> End([Return salted hash])
```

## Failure and edge-case behavior

- `GetLegacyWebEntryAssembly()` falls back to stack-frame heuristics only when the standard entry-assembly discovery methods return nothing, so its result is best-effort in atypical hosting scenarios.
- `ComputeHashNow` intentionally skips the time-based salt wrapper, so its output cannot later be validated for age through [Validate system hash lifetime](validate-system-hash-lifetime.md).
- The salting behavior itself is implemented entirely by the external `SAIF.HashUtil` package; this operation only supplies the payload being salted.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Dependencies](../dependencies.md)

## Sources
- SAIF.Framework.Security.EnvironmentApi\Services.Common\SystemHashUtil.cs
