iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

SHA-2 / SHA-3 / BLAKE3

Cryptographic hashes turn arbitrary input into a fixed-size digest. Modern choice: SHA-256 / SHA-3 / BLAKE3 for integrity; HMAC-SHA-256 for keyed integrity; argon2id / scrypt / bcrypt for passwords.

SHA-256, HMAC, password vs file hash

EXAMPLE
// 1) File / integrity hash — SHA-256 is the modern default
import crypto from 'node:crypto';

const digest = crypto.createHash('sha256').update('hello world').digest('hex');
// e.g. 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'

// 2) Stream a big file
import { createReadStream } from 'node:fs';
import { pipeline } from 'node:stream/promises';

async function fileHash(path) {
    const hash = crypto.createHash('sha256');
    await pipeline(createReadStream(path), hash);
    return hash.digest('hex');
}

// 3) Compare digests in constant time
const ok = crypto.timingSafeEqual(Buffer.from(actual, 'hex'), Buffer.from(expected, 'hex'));
// Never use === — vulnerable to timing attacks for secret-prefix comparisons.

// 4) HMAC — keyed hash for integrity + authenticity
const key = crypto.randomBytes(32);
const sig = crypto.createHmac('sha256', key).update(message).digest('hex');

// Verify
const expectedSig = crypto.createHmac('sha256', key).update(message).digest('hex');
const verified = crypto.timingSafeEqual(Buffer.from(sig, 'hex'), Buffer.from(expectedSig, 'hex'));

// 5) HMAC for webhook signatures (Stripe, GitHub, Slack patterns)
function signWebhook(body, secret) {
    return crypto.createHmac('sha256', secret).update(body).digest('hex');
}

function verifyWebhook(body, signature, secret) {
    const expected = signWebhook(body, secret);
    return crypto.timingSafeEqual(Buffer.from(signature, 'hex'), Buffer.from(expected, 'hex'));
}

// 6) Password hashing — NEVER use raw SHA-256 / SHA-512 for passwords
// Passwords need a slow, salted, memory-hard function (argon2id, scrypt, bcrypt).

import argon2 from 'argon2';

// Hash
const hash = await argon2.hash(password, {
    type:        argon2.argon2id,
    memoryCost:  19 * 1024,   // 19 MB — OWASP 2024 baseline
    timeCost:    2,
    parallelism: 1,
});

// Verify
const valid = await argon2.verify(hash, attempt);

// Why slow + memory-hard:
//   SHA-256(password) is ~10ns. A GPU brute-forces 10^10 candidates/sec.
//   argon2id at 19MB takes ~250ms. Same GPU: 4 attempts/sec.

// 7) Hash algorithms and their use
// SHA-256          : default file/data integrity, signatures, blockchain
// SHA-512          : 64-bit platforms — slightly faster; same security as SHA-256
// SHA-3 (Keccak)   : alternative algorithm family; no real-world break of SHA-2 either
// BLAKE2 / BLAKE3  : faster than SHA-256, equally secure; BLAKE3 supports parallel
// MD5              : BROKEN. Don't use for security. OK for non-security checksums (cache keys).
// SHA-1            : BROKEN. Same as MD5. Used in legacy git, but git is migrating.

// 8) Python — hashlib
import hashlib
digest = hashlib.sha256(data).hexdigest()

import hmac
sig = hmac.new(key, message, hashlib.sha256).hexdigest()
verified = hmac.compare_digest(sig, expected_sig)

# Password
from argon2 import PasswordHasher
ph = PasswordHasher(memory_cost=19 * 1024, time_cost=2, parallelism=1)
hashed = ph.hash(password)
ph.verify(hashed, attempt)

// 9) PHP — hash + password_hash
$digest = hash('sha256', $data);
$sig    = hash_hmac('sha256', $message, $key);
hash_equals($expected, $actual);     // constant-time

// Passwords
$hash = password_hash($password, PASSWORD_ARGON2ID);
password_verify($attempt, $hash);

// 10) Java — MessageDigest + Mac
import java.security.MessageDigest;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(message);

Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
byte[] sig = mac.doFinal(message);

// 11) Salting — for password hashes
// argon2 / scrypt / bcrypt embed a unique random salt in the hash output.
// If you must hash low-entropy data with SHA-256 (NOT recommended for passwords), salt it:
const salt = crypto.randomBytes(16);
const digest = crypto.createHash('sha256').update(Buffer.concat([salt, data])).digest();
// Store salt + digest together.

// 12) HKDF — derive keys from a high-entropy secret
const key = crypto.hkdfSync('sha256', sharedSecret, salt, info, 32);
// Use after ECDH key exchange, or to derive multiple keys from one master.

// 13) Hash-based proofs of work (Bitcoin, Argon2 for PoW)
// Find a nonce such that hash(data || nonce) < target. Difficulty adjusts.

// 14) Common bugs
//   • Storing SHA-256 of a password → GPU brute-force
//   • Comparing digests with === → timing attack on secret prefixes
//   • Using MD5 / SHA-1 for new security designs
//   • Hashing untrusted JSON without canonicalisation → same data, different hash
//   • Not salting before hashing low-entropy data
//   • Using a secret as a key in a hash() instead of HMAC

// 15) Use cases at a glance
// File / blob integrity            → SHA-256 digest (store + compare)
// Webhook signature                → HMAC-SHA-256 with shared secret
// Password storage                 → argon2id / scrypt / bcrypt
// JWT signing (HMAC variant)       → HS256, but prefer RS256 / EdDSA in distributed systems
// Content addressing (caches, blockchains, git)  → SHA-256 / BLAKE3
// Deterministic ID from input      → SHA-256 truncated to 16 bytes
// Rate-limit bucket key (low-secrecy)             → SHA-256 of (ip + endpoint + minute)

// 16) Best practices
//   • For new code: SHA-256 (or BLAKE3 for speed) — never MD5 / SHA-1
//   • Passwords: argon2id with OWASP params + check against HaveIBeenPwned
//   • Signatures over secrets: HMAC — never raw hash with the secret in the input
//   • Compare digests with timingSafeEqual / hmac.compare_digest / hash_equals
//   • Hash data BEFORE signing — sign the hash, not the whole payload (efficiency)
//   • For long-term archival, document the algorithm + parameters so migration is possible

Why it matters

Different problems, different hash families: SHA-256/BLAKE3 for data integrity, HMAC-SHA-256 for keyed signatures, argon2id for passwords. Never reach for fast hashes on low-entropy inputs — they’re crackable in hours.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Fast cryptographic hashes for INTEGRITY (not passwords):
//   SHA-256 / SHA-512 — broadly compatible.
//   SHA-3 / BLAKE3   — modern, fast, no length-extension issues.
// NEVER use these on passwords — see the password track.
Try it Yourself »

Discussion

Loading…