hash encryption security developer-tools

Understanding Hash Functions: A Developer's Guide to MD5, SHA-256, and Beyond

UseEasyTool Team Developer Tools
August 11, 2026 9 min read

Hash functions are one of those things every developer uses but few truly understand. You hash passwords, verify file integrity, generate cache keys, and sign API requests, all relying on functions you probably could not explain in detail. That is usually fine, until you pick the wrong hash for a security-sensitive task and things break.

This guide covers what hash functions are, how the common algorithms differ, and which one to reach for in each situation. No cryptography PhD required.

What Is a Hash Function?

A hash function takes an input of any size and produces a fixed-size output called a hash or digest. The same input always produces the same output. Different inputs should produce different outputs. The output looks random but is fully deterministic.

SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256("Hello") = 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969

Notice that changing a single character from lowercase h to uppercase H completely changes the hash. This is called the avalanche effect, and it is a core property of cryptographic hash functions. A small change in the input cascades through the algorithm and produces a totally different output.

A good cryptographic hash function has four properties:

  • Deterministic: The same input always produces the same hash.
  • Fast to compute: Given an input, the hash is computed quickly.
  • One-way (preimage resistant): Given a hash, you cannot feasibly reverse it to find the original input.
  • Collision resistant: It is computationally infeasible to find two different inputs that produce the same hash.

Try This Tool

Put what you just read into practice — open the tool now.

Open Tool →

Common Hash Algorithms Compared

There are dozens of hash algorithms, but in practice you will encounter four families. Here is how they compare.

Algorithm Output Size Security Status Speed Best Use Case
MD5 128 bits (32 hex chars) Broken Very fast Checksums, non-security tasks
SHA-1 160 bits (40 hex chars) Broken Fast Legacy systems only
SHA-256 256 bits (64 hex chars) Secure Moderate General-purpose, passwords, signatures
SHA-512 512 bits (128 hex chars) Secure Moderate High-security applications
SHA-3 224-512 bits Secure Moderate Future-proofing, alt to SHA-2

MD5: Fast but Broken

MD5 was designed in 1991 by Ronald Rivest. It produces a 128-bit hash and was widely used for checksums and digital signatures. In 2004, researchers demonstrated practical collision attacks, meaning they could find two different inputs that produce the same MD5 hash. By 2008, attacks improved to the point where collisions could be generated in seconds on a standard laptop.

MD5 is still fine for non-security tasks like file integrity checks in non-adversarial contexts or cache key generation. But never use it for passwords, digital signatures, or anything where an attacker could exploit a collision.

MD5("hello") = 5d41402abc4b2a76b9719d911017c592

SHA-1: Also Broken

SHA-1 was the successor to MD5, producing a 160-bit hash. It was the default for Git commit IDs, TLS certificates, and many other systems for years. In 2017, Google and CWI Amsterdam published the SHAttered attack, which produced a practical SHA-1 collision.

Git has since migrated to SHA-256 for new repositories. Most browsers and CAs have dropped SHA-1 certificate support. If you encounter SHA-1 in a codebase, plan to migrate.

SHA-1("hello") = aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d

SHA-256: The Current Standard

SHA-256 is part of the SHA-2 family, designed by the NSA and published in 2001. It produces a 256-bit hash and has no known practical attacks. It is the default hash for TLS, Bitcoin, SSH keys, and most modern security systems. If you are not sure which hash to use, use SHA-256.

SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

SHA-512: More Bits, Same Family

SHA-512 is the 512-bit variant of SHA-2. On 64-bit systems, it is actually faster than SHA-256 because the internal operations use 64-bit words. The longer output provides extra security margin, though 256 bits is already more than sufficient for any realistic threat model.

SHA-512("hello") = 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043

Practical Use Cases for Hash Functions

Hash functions show up everywhere in software development. Here are the most common scenarios and the right algorithm for each.

Password Storage

Never store passwords in plaintext. Never store them with a plain hash like SHA-256(password) either. Plain hashes are vulnerable to rainbow table attacks and brute-force attacks using GPU-accelerated tools that compute billions of hashes per second.

Use a purpose-built password hashing function instead. These are deliberately slow and incorporate a salt to defeat rainbow tables:

  • Bcrypt: The most widely used password hash. Tunable cost factor. Battle-tested.
  • Argon2: Winner of the 2015 Password Hashing Competition. Resistant to GPU and ASIC attacks. Recommended for new projects.
  • scrypt: Memory-hard alternative. Used by some crypto wallets and authentication systems.
// Node.js: hashing a password with bcrypt
const bcrypt = require('bcrypt');
const saltRounds = 12;

const hash = await bcrypt.hash('mypassword', saltRounds);
// => $2b$12$N9qo8uLOickgx2ZMRZoMye...

// Verifying later
const match = await bcrypt.compare('mypassword', hash);
// => true

If you are stuck with SHA-256 for password hashing (some legacy systems require it), at minimum use HMAC with a server-side secret key and a per-user salt. Our HMAC generator can help you test HMAC outputs. But really, just use bcrypt or Argon2.

File Integrity and Checksums

Hashing is the standard way to verify that a file has not been tampered with or corrupted during transfer. Download a file, compute its hash, and compare against the published checksum. If they match, the file is intact.

# Verify a downloaded file on Linux/macOS
sha256sum ubuntu-26.04.iso
# Output: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  ubuntu-26.04.iso

# Compare against the official checksum
echo "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  ubuntu-26.04.iso" | sha256sum -c
# Output: ubuntu-26.04.iso: OK

For file integrity, MD5 is still commonly used because it is fast and the threat model does not usually involve adversarial collision attacks. But SHA-256 is the better default and is what most modern software distributions publish.

Data Deduplication

If you store files or content and want to detect duplicates, hashing is the answer. Compute a hash of each file's content and use it as a deduplication key. Two files with the same hash are almost certainly identical.

// JavaScript: deduplicate an array of strings by content hash
async function sha256(text) {
  const data = new TextEncoder().encode(text);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  return Array.from(new Uint8Array(hashBuffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

const files = ['file A content', 'file B content', 'file A content'];
const seen = new Map();

for (const content of files) {
  const hash = await sha256(content);
  if (!seen.has(hash)) {
    seen.set(hash, content);
  }
}

console.log(seen.size); // 2 (one duplicate removed)

Cache Keys

When you need a stable, compact key for caching, hashing the input data gives you a consistent identifier. This is common in CDNs, memoization, and database query caches.

// Memoization cache keyed by argument hash
const cache = new Map();

function memoize(fn) {
  return async function(...args) {
    const key = await sha256(JSON.stringify(args));
    if (cache.has(key)) return cache.get(key);

    const result = await fn(...args);
    cache.set(key, result);
    return result;
  };
}

For cache keys, MD5 or even a non-cryptographic hash like xxHash works fine. Security is not the concern here, speed is.

Digital Signatures and HMAC

When you need to verify that a message came from a specific sender and was not modified in transit, you use either a digital signature (asymmetric) or HMAC (symmetric). Both rely on hash functions internally.

HMAC combines a hash function with a secret key. The recipient, who also knows the key, can recompute the HMAC and verify authenticity. HMAC-SHA256 is the standard choice for API authentication, webhook signing, and JWT signatures.

// Node.js: HMAC-SHA256 for API request signing
const crypto = require('crypto');

const secret = 'your-api-secret';
const payload = JSON.stringify({ action: 'transfer', amount: 100 });

const signature = crypto
  .createHmac('sha256', secret)
  .update(payload)
  .digest('hex');

// => "c7d9b0e3f2a1..."

// Send payload + signature to server
// Server recomputes HMAC and compares

You can test HMAC generation with our free HMAC generator to make sure your signatures match between client and server.

Generating Hashes in Different Languages

Every modern language has hash functions built in or available through a standard library. Here are quick examples for the three most common languages.

JavaScript (Browser and Node.js)

// Browser: using Web Crypto API
async function sha256(message) {
  const data = new TextEncoder().encode(message);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

await sha256('hello');
// => "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

// Node.js: using the crypto module
const crypto = require('crypto');

crypto.createHash('sha256').update('hello').digest('hex');
// => "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

crypto.createHash('md5').update('hello').digest('hex');
// => "5d41402abc4b2a76b9719d911017c592"

Python

import hashlib

# SHA-256
hashlib.sha256(b'hello').hexdigest()
# => '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'

# MD5
hashlib.md5(b'hello').hexdigest()
# => '5d41402abc4b2a76b9719d911017c592'

# SHA-512
hashlib.sha512(b'hello').hexdigest()
# => '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca7...'

Go

package main

import (
	"crypto/sha256"
	"fmt"
)

func main() {
	h := sha256.Sum256([]byte("hello"))
	fmt.Printf("%x\n", h)
	// => 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
}

Using a Free Online Hash Generator

Sometimes you just need to hash a string quickly without writing code. Maybe you are debugging an API signature, verifying a checksum, or checking what a specific input hashes to. Our free online hash generator supports MD5, SHA-1, SHA-256, SHA-512, and SHA-3, all in one place.

The tool runs entirely in your browser. Your input never leaves your device, which matters when you are hashing sensitive data like API keys or internal identifiers. You can hash the same input with multiple algorithms simultaneously and compare outputs side by side.

For more advanced use cases, we also have a free HMAC generator for keyed hashing and an AES encryption tool for when you need two-way encryption rather than one-way hashing.

Hashing vs Encryption: Know the Difference

This trips up junior developers all the time. Hashing is one-way. Encryption is two-way.

A hash function cannot be reversed. You hash a password to store it, and to verify a login you hash the submitted password and compare the hashes. You never decrypt the stored hash back to the original password.

Encryption, on the other hand, is reversible. You encrypt data with a key, and someone with the right key can decrypt it back to the original. Use encryption when you need to recover the original data. Use hashing when you do not.

Property Hashing Encryption
Direction One-way Two-way (encrypt + decrypt)
Key required No (HMAC uses a key) Yes
Output size Fixed Variable (similar to input)
Use case Passwords, checksums, signatures Confidential data, communications
Example SHA-256, bcrypt AES, RSA

Security Best Practices

Here is a quick checklist for using hash functions safely in production:

  • Use SHA-256 as your default. It is secure, widely supported, and fast enough for most use cases.
  • Never hash passwords with plain SHA-256. Use bcrypt, Argon2, or scrypt instead. These are designed to be slow, which defeats brute-force attacks.
  • Do not use MD5 or SHA-1 for security. They are broken. Stick to legacy or non-security use cases only.
  • Always salt passwords. A salt is a random value added to the password before hashing. It ensures that two users with the same password get different hashes. Bcrypt and Argon2 handle salting automatically.
  • Use HMAC for message authentication. A plain hash does not prove authenticity because anyone can compute it. HMAC requires a secret key, so only someone with the key can produce a valid signature.
  • Use constant-time comparison when comparing hashes for authentication. A standard string comparison can leak information through timing attacks. Most crypto libraries provide a constant-time compare function.
// Node.js: constant-time comparison
const crypto = require('crypto');

// BAD - vulnerable to timing attacks
if (receivedHash === expectedHash) { ... }

// GOOD - constant-time comparison
if (crypto.timingSafeEqual(
  Buffer.from(receivedHash, 'hex'),
  Buffer.from(expectedHash, 'hex')
)) { ... }

Wrapping Up

Hash functions are a foundational tool in software development. You do not need to understand the math behind the SHA-2 compression function to use them correctly, but you do need to know which algorithm to pick and when hashing is the right tool versus encryption.

The short version: use SHA-256 for general-purpose hashing and checksums, use bcrypt or Argon2 for passwords, use HMAC for message authentication, and avoid MD5 and SHA-1 for anything security-related. When you need to quickly hash a string without writing code, use our free online hash generator. For keyed hashing, try the HMAC tool. And if you need reversible encryption rather than one-way hashing, our AES encryption tool has you covered.

Get those basics right, and you will avoid the most common hashing mistakes that lead to security vulnerabilities.

Related Articles

Hash Generator Tool

Generate MD5, SHA-1, SHA-256, SHA-512, and SHA-3 hashes online for free. Runs entirely in your browser.

Understanding AES Encryption

Deep dive into AES encryption: how the algorithm works, key sizes, modes of operation, and practical applications.

View All Articles

Browse our complete collection of developer tutorials, guides, and tips.