# Crypto.Sha256Hex

> SHA-256 of a string's UTF-8 bytes as 64-character lowercase hex — the secure default hash. Deterministic, so it pushes down into SQL. Use it wherever the input could be attacker-influenced; use Crypto.HmacSha256Hex to authenticate a message, and Security.HashPassword for passwords.

<!-- id: function-crypto-sha256hex · area: function · stability: stable · html: https://osysharp.com/reference/function/crypto-sha256hex/ -->

## Summary        {#summary}
`Crypto.Sha256Hex(s)` returns the SHA-256 digest of `s`'s UTF-8 bytes as a **64-character lowercase hex string** —
the C# `Convert.ToHexString(SHA256.HashData(...)).ToLowerInvariant()` form. It is the **secure default hash**: reach
for this one unless you specifically need a non-adversarial checksum.

## Signature      {#signature}
```osy syntax
Crypto.Sha256Hex(<string> s) -> string
```

## Description    {#description}
SHA-256 is **collision-resistant**: nobody can construct two different inputs with the same digest. That is what makes
it safe to use on values an attacker can influence — which is the property [Crypto.Md5Hex](https://osysharp.com/reference/function/crypto-md5hex/) lacks.

It is deterministic, so the same input always produces the same digest, and it **pushes down into SQL**: inside a query
it renders as Postgres's `sha256()` over the UTF-8 bytes, hex-encoded, producing results byte-identical to the
in-memory version. So a fingerprint you compute in a function matches one you filter on in a query.

**What a hash does and does not prove.** A hash proves **integrity** of a value you already trust — recompute it and
compare to detect corruption or change. It does **not authenticate** a value you received from someone else: an
attacker who can change the value can simply recompute its hash to match. To authenticate a message, you need the
keyed construction — [Crypto.HmacSha256Hex and Crypto.FixedTimeEquals](https://osysharp.com/reference/function/crypto-hmac/).

**Not for passwords.** A password hash must be deliberately *slow* to resist brute force; SHA-256 is designed to be
fast, which is exactly wrong for credentials. Use `Security.HashPassword` (BCrypt), which also salts for you.

## Examples       {#examples}
Fingerprint content to skip redundant work, and detect tampering in transit:

```osy title="content fingerprint + integrity check" test app=crypto-hashing
class Document {
  public string Body;
  public string Fingerprint;
}

// Skip expensive downstream work when the content is unchanged.
bool NeedsReprocessing(string content, string storedHash) {
  return Crypto.Sha256Hex(content) != storedHash;
}

// Detect corruption of a value we stored ourselves.
bool IsIntact(Document doc) {
  return Crypto.Sha256Hex(doc.Body) == doc.Fingerprint;
}
// Crypto.Sha256Hex("abc") -> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
```

## See also       {#see-also}
- [Crypto.HmacSha256Hex and Crypto.FixedTimeEquals](https://osysharp.com/reference/function/crypto-hmac/) — authenticate a message you received (keyed; a plain hash cannot do this)
- [Crypto.Md5Hex](https://osysharp.com/reference/function/crypto-md5hex/) — the fast non-adversarial checksum, and why it must not be used for security
