CryptoSecurityHashing

Cryptographic Hashes Explained

March 15, 2026·6 min read

Hashing appears in checksums, signatures, password storage, package verification, and build pipelines. The terminology is familiar, but the implementation details are often misunderstood. This guide explains what hash functions do well, where older algorithms fail, and how to use them responsibly in everyday engineering work.

This generated value is referred to as the hash, digest, or checksum.

1. MD5 Message-Digest Algorithm

MD5 outputs a 128-bit hash value that typically displays as a 32-digit hexadecimal block. It was heavily used in the 1990s to secure file transfers and simple hashes.

Status: Broken. Due to collisions (when two completely different files generate the same exact MD5 hash), MD5 is widely considered unsafe for security applications. It is strictly recommended only for basic integrity checks against non-malicious errors.

2. Secure Hash Algorithm (SHA-1)

SHA-1 produces a larger 160-bit hash. Adopted actively by SSL certificates, Git revision controls, and password stores around the turn of the century.

Status: Obsolete for passwords/security. In 2017, a joint strike force by CWI Amsterdam and Google successfully demonstrated an identical SHA-1 hash collision between two distinct PDF documents, famously known as the SHAttered attack.

3. SHA-256 (SHA-2 Family)

Currently the industry standard. This function generates an almost uncrackable 256-bit hash.

Status: Highly Secure. SHA-256 powers Bitcoin's proof-of-work mechanism, verifies modern SSL certificates, and is considered secure against known mathematical attacks.

4. Implementation: Hashing in the Browser

Use Web Crypto API for SHA-256 (native, no deps). For MD5/SHA-1, use crypto-js:

// Web Crypto API (SHA-256 only, async)
async function sha256(text) {
  const buf = new TextEncoder().encode(text);
  const hash = await crypto.subtle.digest('SHA-256', buf);
  return Array.from(new Uint8Array(hash))
    .map(b => b.toString(16).padStart(2, '0')).join('');
}

// crypto-js (MD5, SHA1, SHA256, SHA512)
import cryptoJs from 'crypto-js';

const md5 = cryptoJs.MD5('hello').toString();
const sha256 = cryptoJs.SHA256('hello').toString();

For Webhook HMAC verification: crypto.subtle.sign('HMAC', key, payload) — compare result with the header signature.

5. Characteristics of Good Hashes

All major hash functions guarantee three specific behaviors:

  • Deterministic: The same input will forever generate the exact same resulting checksum.
  • Avalanche Effect: Changing just one bit of data alters the entire hash completely.
  • One-Way Function: Although you can encode "hello" into a hash easily, it is computationally impossible to "decode" that hash back into "hello" mathematically.

6. Conclusion

Stop using MD5 and SHA-1 for passwords! Use SHA-256 (or better yet, bcrypt/argon2 specifically tailored for passwords).

Use the Hash Generator to generate common digests locally in the browser.

7. Choosing the right algorithm by task

  • File integrity checks: SHA-256 is a safe default.
  • Message authenticity: use HMAC-SHA256 with a shared secret.
  • Password storage: use bcrypt, scrypt, or argon2 (not raw SHA-256).
  • Legacy compatibility: MD5/SHA-1 only when protocol constraints force it.

8. Common implementation pitfalls

  • Hashing parsed JSON directly: key ordering differences can change the digest unexpectedly.
  • Ignoring encoding: UTF-8 vs UTF-16 mismatches produce different hashes.
  • Using simple equality checks: compare MACs in constant time for security-sensitive paths.
  • Confusing hash with encryption: hashes are one-way and cannot be decrypted.

9. Quick security checklist

  1. Use SHA-256 or stronger for new integrity workflows.
  2. Use dedicated password KDFs for credential storage.
  3. Standardize text encoding before hashing.
  4. Document algorithm choice and migration path in your security docs.