Hash Generator

Compute MD5, SHA-1, SHA-256, and SHA-512 digests from any text. All four hashes are generated simultaneously — pick the one you need.

By Pankaj Kumar · DevToolsHub · Last updated Jun 2026

Hashing in .NET: the problems I actually solve with it

In my ASP.NET Core projects, I reach for hashing in three situations: verifying incoming webhook payloads from Stripe or GitHub using HMAC-SHA256, generating ETag header values from response content for HTTP caching, and checking whether a large file or blob has changed before processing it. System.Security.Cryptography covers all three cases without a NuGet package, but the API is verbose enough that it's worth understanding before you write it.

Hashing in .NET: System.Security.Cryptography

The BCL's System.Security.Cryptography namespace provides SHA-256, SHA-512, and MD5 as static one-shot methods in .NET 5+ via SHA256.HashData() and as disposable instances for streaming scenarios. HMAC is available as HMACSHA256, which is what you need for webhook signature verification:

// Verify a GitHub or Stripe webhook payload using HMAC-SHA256
// The secret is stored in your configuration (never hardcoded)
var secret = Encoding.UTF8.GetBytes(configuration["Webhooks:Secret"]!);
var payload = await request.Body.ReadToEndAsync();
var payloadBytes = Encoding.UTF8.GetBytes(payload);

using var hmac = new HMACSHA256(secret);
var computedHash = hmac.ComputeHash(payloadBytes);
var computedSignature = Convert.ToHexString(computedHash).ToLower();

// GitHub format: "sha256=abc123..."
var receivedSignature = request.Headers["X-Hub-Signature-256"].ToString()
    .Replace("sha256=", "");

// Use CryptographicOperations.FixedTimeEquals to prevent timing attacks
var isValid = CryptographicOperations.FixedTimeEquals(
    Encoding.UTF8.GetBytes(computedSignature),
    Encoding.UTF8.GetBytes(receivedSignature)
);

The critical detail is CryptographicOperations.FixedTimeEquals. A plain string comparison exits early on the first mismatch, which leaks information about where the signatures diverge — a timing attack. FixedTimeEquals always takes the same amount of time regardless of where (or whether) the values differ.

Algorithm comparison table

Algorithm Standard Output bits Hex string length Security status Typical use
MD5 RFC 1321 (1992) 128 bits 32 characters Broken — collision attacks practical (2004) Non-security checksums, cache keys, ETags, deduplication identifiers
SHA-1 FIPS 180-1 (1995) 160 bits 40 characters Broken — SHAttered collision (2017) Git object addressing (legacy), TLS/code-signing revoked, not for new systems
SHA-256 FIPS 180-4 (2015) 256 bits 64 characters Secure TLS certificates, code signing, blockchain (Bitcoin), JWT HS256, Docker image digests, HMAC-SHA256
SHA-512 FIPS 180-4 (2015) 512 bits 128 characters Secure High-security archival hashing, password KDFs (PBKDF2 inner hash), systems requiring >256-bit output

How SHA-256 works — the Merkle-Damgård construction

SHA-256 is built on the Merkle-Damgård construction, defined in FIPS PUB 180-4 (Secure Hash Standard). Understanding the internals explains why the algorithm has the properties it does and why changing one byte produces a completely different output.

  1. Pre-processing (padding): The input message is padded to a length that is a multiple of 512 bits. Padding appends a single 1 bit, then enough 0 bits, then a 64-bit big-endian encoding of the original message length. This ensures every input maps to a unique padded representation.
  2. Block splitting: The padded message is split into 512-bit (64-byte) blocks. Each block is processed sequentially through the compression function.
  3. Message schedule: Each 512-bit block is expanded from 16 32-bit words into a 64-word message schedule using bit rotation and XOR operations. This expansion means every bit of the original block influences 64 rounds of mixing.
  4. 64 compression rounds: SHA-256 maintains 8 working variables (a–h), each 32 bits wide, initialised to the fractional parts of the square roots of the first 8 prime numbers. In each round, the working variables are mixed using bitwise operations (AND, OR, XOR), modular addition, and bit rotation by constants derived from the cube roots of the first 64 primes. The output of one round feeds directly into the next.
  5. State update: After all 64 rounds, the round output is added (modulo 2³²) to the previous hash state. This addition is the source of the chaining — the full history of every prior block is folded into the current state.
  6. Final hash: After the last block, the 8 working variables are concatenated to produce the 256-bit (32-byte) hash, typically displayed as a 64-character hexadecimal string.

The reason a one-bit change to the input produces a completely different hash is that the changed bit propagates through the message schedule expansion and then through 64 rounds of nonlinear mixing — each round amplifying the change until essentially every output bit is affected. This is the avalanche effect.

HMAC — Hash-based Message Authentication Code

A plain hash (SHA-256) only tells you whether data has changed — it does not tell you who produced it. Any attacker who knows your data can recompute the SHA-256 hash and produce a valid-looking value. HMAC (defined in RFC 2104) combines the hash function with a secret key to produce a value that only someone who knows the key can reproduce.

HMAC-SHA256 is computed as:

HMAC(key, message) = SHA256((key ⊕ opad) ∥ SHA256((key ⊕ ipad) ∥ message))

where opad is the outer padding (0x5c repeated) and ipad is the inner padding (0x36 repeated). The double-hash construction prevents length-extension attacks that affect plain SHA-256 when a secret prefix is naively prepended.

HMAC-SHA256 is used in: JWT tokens with algorithm HS256, AWS Signature Version 4 request signing, Webhook payload verification (GitHub, Stripe, Twilio), and TOTP/HOTP one-time password generation.

Why you must never hash passwords directly with SHA-256

SHA-256 is intentionally fast — a modern GPU (NVIDIA RTX 4090) can compute approximately 22 billion SHA-256 hashes per second. This speed is desirable for file integrity checking but catastrophic for password storage. An attacker with a leaked database of SHA-256-hashed passwords can test every common password and dictionary word in seconds.

For password storage, use a dedicated slow hashing function:

  • bcrypt: Industry standard. Work factor of 12+ takes ~250ms per hash, making bulk cracking impractical. Used by default in most authentication frameworks (Devise, Passport.js, ASP.NET Core Identity).
  • Argon2id: Winner of the Password Hashing Competition (2015). Configurable memory and CPU cost. The current recommended choice for new systems. Resistant to GPU and ASIC acceleration due to its memory-hard design.
  • PBKDF2-SHA256: Approved by NIST (SP 800-132). Uses SHA-256 internally but iterates it 600,000+ times (NIST 2023 recommendation). Required for FIPS compliance environments.

All three algorithms include a built-in random salt — a random value unique to each user generated at password creation time. The salt ensures that two users with the same password produce different stored hashes, defeating rainbow table attacks entirely.

Hash salting and rainbow table resistance

A rainbow table is a precomputed lookup table mapping common passwords to their hashes. Without salting, an attacker with a leaked hash database can find any password that appears in the table with a single lookup. Salting defeats this by making every hash unique even for identical passwords: the input to the hash function is concat(salt, password), and the attacker would need a separate table for every possible salt value — a storage and compute requirement that makes precomputation infeasible.

The salt does not need to be secret — it is typically stored in the same database row as the hash. Its only purpose is uniqueness. An effective salt is at least 16 bytes of cryptographically random data generated with a secure random number generator (crypto.randomBytes in Node.js, secrets.token_bytes in Python, crypto/rand in Go).

Five real .NET use cases

  1. Verifying a GitHub or Stripe webhook signature in ASP.NET Core. Both platforms sign the request body with HMAC-SHA256 using a shared secret. Compute HMACSHA256.HashData(secretBytes, payloadBytes), convert to hex, and compare using CryptographicOperations.FixedTimeEquals to prevent timing attacks.
  2. Generating an HTTP ETag for a JSON response in a .NET API. Hash the serialized response body with SHA256.HashData(responseBytes), encode as hex or Base64, and set it as the ETag response header. The client sends If-None-Match on the next request; a 304 avoids resending the payload.
  3. Detecting whether an uploaded file has changed before reprocessing it in a background job. Store the SHA-256 of the file at upload time. When the job runs, recompute the hash of the stored file and compare. A mismatch means the file was replaced or corrupted.
  4. Content-addressing blobs stored in Azure Blob Storage or AWS S3. Use SHA256.HashData(fileBytes) as the blob name (or a metadata property). Identical files produce identical hashes and can be stored once regardless of how many records reference them.
  5. Generating idempotency keys for outbound API calls from a .NET worker service. Hash a deterministic string that combines the entity ID and operation type: Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes($"{orderId}:charge"))). Sending the same idempotency key twice on a Stripe or Adyen call replays the original result instead of charging twice.

Data processing

When you click Hash, your input text is sent over HTTPS to the DevToolsHub API (hosted on Microsoft Azure). The API computes all four hashes using .NET's System.Security.Cryptography library and returns the results immediately. The API does not log request payloads — only operational metadata (response status code, latency) is retained for 24 hours. See the Privacy Policy for full details.

Frequently asked questions

Which .NET method should I use for SHA-256: SHA256.HashData or SHA256.Create? Use SHA256.HashData(ReadOnlySpan<byte>) (available .NET 5+) for one-shot hashing of an in-memory value — it is allocation-efficient and avoids the dispose pattern. Use SHA256.Create() wrapped in using only when you need to hash a stream incrementally with ComputeHash(Stream).

Can I use SHA-256 to store passwords in ASP.NET Core? No. SHA-256 is far too fast for password storage — a modern GPU can compute 22 billion SHA-256 hashes per second. Use ASP.NET Core Identity's built-in IPasswordHasher<T>, which uses PBKDF2-SHA256 with 600,000 iterations by default in .NET 8. If you need bcrypt or Argon2id, add the BCrypt.Net-Next or Isopoh.Cryptography.Argon2 NuGet packages.

Why should I use CryptographicOperations.FixedTimeEquals instead of string comparison for HMAC verification? A regular == comparison exits as soon as it finds the first differing character. An attacker can measure how long your comparison takes to find progressively closer fakes, eventually reconstructing the expected value one character at a time. FixedTimeEquals always takes the same amount of time regardless of where the values differ.

Is MD5 safe to use in a .NET application? MD5 is safe for non-security uses: cache keys, ETag values, deduplication identifiers, and content fingerprints where an adversary cannot influence the input. It is unsafe for anything requiring collision resistance or pre-image resistance — including signatures, certificate fingerprints, and file integrity verification where tampering is a threat.

This tool is built with ASP.NET Core 8, Blazor Server, and System.Security.Cryptography. It runs securely on Microsoft Azure.

Native code equivalents

Production-ready snippets — same logic the tool runs, in your language
Your data is processed within your active session only · Never stored or logged
Node.js
Python
Go
openssl / bash
// Node.js built-in crypto — no npm package required
const crypto = require('crypto');

// SHA-256 (recommended default for security-sensitive use)
const sha256 = (text) => crypto.createHash('sha256').update(text, 'utf8').digest('hex');

// SHA-512
const sha512 = (text) => crypto.createHash('sha512').update(text, 'utf8').digest('hex');

// MD5 (non-security use only — checksums, cache keys, ETags)
const md5 = (text) => crypto.createHash('md5').update(text, 'utf8').digest('hex');

// HMAC-SHA256 — used for JWT signing (HS256) and API authentication
const hmacSha256 = (text, secret) =>
  crypto.createHmac('sha256', secret).update(text, 'utf8').digest('hex');

console.log(sha256('DevToolsHub'));
// 3e71e0b23d4b6b2f3e3f6f8e0d3e7e5a...

// Hash a file (Node.js streams)
const fs = require('fs');
const hash = crypto.createHash('sha256');
fs.createReadStream('file.txt').pipe(hash).on('finish', () => {
  console.log('File SHA-256:', hash.digest('hex'));
});
Your input stays private. All processing happens in-memory on the server and is never stored, logged, or associated with your identity. Sensitive data — tokens, signing keys, and passwords — is safe to use here.
Input Section

Input text

DevToolsHub
Output Section
MD5

3500c827000bded5b76acb2edfb42fb2

SHA-1

c6506e8042334d9ac0aac210772160893d954f15

SHA-256

2b3d73ec5437a40214ae9a9ce44194353278c695edf7d33a39eb77da6499c48c

SHA-512

06f411707036a632af4ebba87984a3e888f0661463eae9d1197f912200ee01cd7dbbb6df33b6e519d700493d8065bb9e5ece5a4a3b2b9d0bd30a171ed514e38f