Cryptographic Hashing for Developers: MD5, SHA-256, and HMAC Explained

posted 4 min read

Cryptographic hashes appear in password storage, file verification, API authentication, digital signatures, and blockchains. Here's how they work and which one to use for each purpose.

What is a cryptographic hash?

A hash function takes input of any length and produces a fixed-length output. The key properties:

  • Deterministic: The same input always produces the same hash.
  • One-way: You cannot reverse a hash to get the original input.
  • Avalanche effect: A small change in input produces a completely different hash.
  • Collision-resistant: It should be computationally infeasible to find two different inputs that produce the same hash.

A hash generator lets you compute MD5, SHA-1, SHA-256, and SHA-512 from text or files instantly in the browser.

MD5 (128-bit / 32 hex chars)

``

MD5("hello") = 5d41402abc4b2a76b9719d911017c592

`

Status: Cryptographically broken. MD5 is vulnerable to collision attacks — it's possible to find two different inputs with the same MD5 hash in milliseconds with modern hardware.

Use it for: Non-security checksums (detecting accidental corruption), legacy system compatibility, cache keys, non-sensitive data fingerprinting.

Do NOT use it for: Password hashing, digital signatures, security-critical file verification.

SHA-1 (160-bit / 40 hex chars)

<code> <p>SHA-1("hello") = aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d</p> </code>

Status: Cryptographically weak. SHA-1 collision attacks have been practically demonstrated (SHAttered, 2017). Major certificate authorities and Git (for new repos) have moved away from SHA-1.

Use it for: Legacy compatibility only. Old Git commits still use SHA-1. Avoid for new systems.

SHA-256 (256-bit / 64 hex chars)

<code> <p>SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824</p> </code>

Status: Current standard. No known practical attacks. Part of the SHA-2 family (also includes SHA-384, SHA-512).

Use it for: File integrity verification, digital signatures, API request signing, blockchain transactions, HMAC keys, everywhere SHA-1 was used.

SHA-512 (512-bit / 128 hex chars)

<code> <p>SHA-512("hello") = 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043...</p> </code>

Status: Even more resistant than SHA-256. The output is longer (better for collision resistance) but computationally slightly more expensive.

Use it for: When SHA-256 isn't strong enough (extremely high-security scenarios, long-term archival integrity). The extra strength is rarely necessary for most applications.

HMAC: Keyed Hashing

HMAC (Hash-based Message Authentication Code) combines a secret key with the hash to authenticate both data integrity and identity.

<code> <p>HMAC-SHA256(key, message) = a unique hash per key+message pair</p> </code>

Uses: API authentication (signing requests), JWT validation (HS256), webhook verification, session tokens.

How it works:
<code> <p>HMAC(K, m) = H((K' XOR opad) || H((K' XOR ipad) || m))</p> </code>

In practice, you use a library:

<code>javascript <p>// Node.js</p> <p>const crypto = require('crypto');</p> <p>const hmac = crypto.createHmac('sha256', secretKey);</p> <p>hmac.update(message);</p> <p>const signature = hmac.digest('hex');</p> </code>

<code>python <p>import hmac, hashlib</p> <p>signature = hmac.new(secret_key.encode(), message.encode(), hashlib.sha256).hexdigest()</p> </code>

Password hashing: don't use SHA

SHA algorithms are fast — by design. This makes them terrible for password hashing, because an attacker can compute billions of SHA hashes per second on a GPU.

Use purpose-built password hashing algorithms:

  • bcrypt: Adaptive cost factor, resistant to GPU attacks. Standard for most web apps.
  • Argon2: Winner of the Password Hashing Competition (2015). Three variants: Argon2i (side-channel resistant), Argon2d (GPU resistant), Argon2id (both). Recommended for new systems.
  • scrypt: Memory-hard algorithm. Widely used (Litecoin, OpenSSL).

`python
Python: bcrypt
import bcrypt


hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))


is_valid = bcrypt.checkpw(password.encode(), hashed)

Python: Argon2

from argon2 import PasswordHasher

ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=1)

hashed = ph.hash(password)

is_valid = ph.verify(hashed, password)

`

<code>javascript <p>// Node.js: bcrypt</p> <p>const bcrypt = require('bcrypt');</p> <p>const hash = await bcrypt.hash(password, 12);</p> <p>const valid = await bcrypt.compare(password, hash);</p> </code>

File verification

Verifying a downloaded file is intact:

`bash
Linux/macOS
sha256sum downloaded-file.iso # Compute hash


echo "expected_hash downloaded-file.iso" | sha256sum --check # Verify

macOS (alternative)

shasum -a 256 downloaded-file.iso

Windows (PowerShell)

Get-FileHash downloaded-file.iso -Algorithm SHA256

`

In Python:

`python
import hashlib, sys

def file_hash(path, algorithm='sha256'):

h = hashlib.new(algorithm)

with open(path, 'rb') as f:

while chunk := f.read(65536):

h.update(chunk)

return h.hexdigest()

print(file_hash('large-file.iso'))

``

Choosing the right hash function

| Use case | Recommended |

|----------|-------------|

| File integrity check (non-security) | MD5 or SHA-256 |

| File integrity check (security) | SHA-256 |

| Digital signatures | SHA-256 or SHA-512 |

| API request signing | HMAC-SHA256 |

| JWT tokens | HMAC-SHA256 (HS256) or RSA-SHA256 (RS256) |

| Password storage | Argon2id or bcrypt |

| Blockchain | SHA-256 (Bitcoin), Keccak-256 (Ethereum) |

| UUID generation | Not a hash — use crypto.randomUUID() |

Never use MD5 or SHA-1 for anything security-sensitive. SHA-256 covers most needs; add HMAC when you need authentication alongside integrity.

Originally published at https://snappytools.app/hash-generator/

More Posts

Comparison: Universal Import vs. Plaid/Yodlee

Pocket Portfolio - Mar 12

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelskiverified - Mar 19

The Interface of Uncertainty: Designing Human-in-the-Loop

Pocket Portfolio - Mar 10

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelskiverified - Apr 23

Sovereign Intelligence: The Complete 25,000 Word Blueprint (Download)

Pocket Portfolio - Apr 1
chevron_left

Related Jobs

View all jobs →

Commenters (This Week)

3 comments
2 comments
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!