Every time you download a file and see a string of hex characters labeled "SHA-256 checksum," or every time you log into a website whose database was breached and yet your actual password wasn't exposed, hashing is the mechanism working behind the scenes. It's one of those concepts that sounds abstract until you see a concrete example, and then it clicks immediately.
What a hash function actually does
A hash function takes an input of any size — a single character, a whole novel, a multi-gigabyte file — and produces a fixed-size output, called a hash or digest. Feed it the same input twice, and you get the exact same output every time. Change even one character of the input, and the output changes completely and unpredictably.
SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256("hellp") = 3f6f56ecf7fc2ac47ee7a... (completely different, one letter changed)
That second property — a tiny change in input causing a massive, unpredictable change in output — is called the avalanche effect, and it's central to what makes hashing useful.
Property 1: it's one-way
A good hash function is designed so that going from input to hash is fast and easy, but going from a hash back to the original input is, for all practical purposes, impossible — there's no mathematical shortcut, only exhaustively trying inputs until one happens to produce a matching hash. This is exactly why storing a hash of a password, rather than the password itself, is meaningfully safer: even someone with full read access to the hash can't directly reverse it back into the original password.
Property 2: collisions should be effectively impossible to find
Since a hash function maps inputs of any size down to a fixed, limited output size, in theory two different inputs producing the same hash (a "collision") must be possible somewhere — there are simply more possible inputs than possible outputs. What makes a hash function cryptographically strong is that finding two colliding inputs on purpose should be computationally infeasible, even though collisions technically exist. This property is exactly what's broken when a hash function is declared "cryptographically broken."
MD5 and SHA-1: still around, no longer trustworthy for security
MD5 (128-bit output) and SHA-1 (160-bit output) were both once the standard choice, and both have since had practical collision attacks demonstrated — meaning researchers found real, working ways to deliberately construct two different inputs with the same hash. That doesn't make them useless everywhere: they're still commonly used for non-adversarial purposes like verifying a download wasn't corrupted by accident, or quickly checking whether two large files are identical. What it does mean is neither should be trusted anywhere an attacker might deliberately try to create a collision, like digital signatures or SSL certificates.
The SHA-2 family: the current standard
SHA-256 and SHA-512 (with 256-bit and 512-bit outputs respectively) are part of the SHA-2 family and remain cryptographically strong today, with no practical collision attacks known. This is what you'll see used for things like Bitcoin's proof-of-work, TLS certificate signatures, and verifying software package integrity. The bigger output size isn't just about being "more secure" in some vague sense — it makes both guessing an input and constructing a deliberate collision astronomically more expensive.
Why you should never hash a password directly with SHA-256
Here's a genuinely important, commonly misunderstood point: SHA-256 being cryptographically strong does not make it a good choice for hashing passwords, and this trips up more people than you'd expect. SHA-256 is deliberately fast — that's a feature for verifying file integrity, but a serious liability for passwords. An attacker with a stolen database of SHA-256 password hashes can test billions of guessed passwords per second on modern hardware, because each guess is cheap to hash and check. Purpose-built password hashing algorithms like bcrypt, scrypt, and Argon2 are deliberately, tunably slow, and typically add a random "salt" to each password before hashing, which stops attackers from using a single precomputed table of hash results (a "rainbow table") against every user's password at once. If you're building a system that stores passwords, use one of these, never a general-purpose hash function like MD5 or SHA-256 directly.
Practical, everyday uses of hashing
- Verifying downloads. A site publishes a file's SHA-256 checksum; you hash the file you downloaded and compare. A mismatch means corruption or tampering during transfer.
- Detecting duplicate content. Instead of comparing two large files or documents byte-by-byte, compare their hashes — a match strongly suggests identical content.
- Git commit IDs. Every Git commit hash is a SHA-1 hash (Git is transitioning toward SHA-256) of the commit's content, which is how Git can detect if history has been altered.
- Content-addressed storage and caching. Using a file's hash as part of its filename or cache key means the name automatically changes if the content changes, and never collides for unrelated content.
The one-sentence summary
A hash function turns any input into a fixed-size fingerprint that's practically impossible to reverse and extremely unlikely to collide with another input's fingerprint — which is exactly why it's useful for verifying integrity, but only safe for passwords when paired with an algorithm specifically designed to be slow.