Understand how SHA-256 works, what makes it secure, and where it is used in modern software and cryptography.
SHA-256 is a cryptographic hash function that takes an input of any length and produces a fixed-size 256-bit (32-byte) output, typically represented as a 64-character hexadecimal string. It belongs to the SHA-2 family of hash functions, designed by the United States National Security Agency (NSA) and published by the National Institute of Standards and Technology (NIST) in 2001.
The "256" refers to the digest size: no matter what you feed into SHA-256 — a single character, a novel, or a 10 GB video file — the output is always exactly 256 bits long.
Example: the SHA-256 hash of the string "hello" is:
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
And the hash of "hello!" (just one character different) is:
ce06092fb948d9af insert completely different value
This dramatic change from a tiny input difference is called the avalanche effect, and it is one of the defining properties of a secure hash function.
For a hash function to be useful in security contexts, it must satisfy four key properties:
The same input always produces the same output. This is essential for verification — if you hash a file, you must be able to reproduce the exact same hash from the same file.
Given a hash value h, it must be computationally infeasible to find any input m such that hash(m) = h. This is often described as the "one-way" property — you can easily compute a hash from data, but you cannot work backwards from the hash to the data.
Given an input m1, it must be computationally infeasible to find a different input m2 such that hash(m1) = hash(m2). This prevents attackers from substituting an alternative message that hashes to the same value as a legitimate one.
It must be computationally infeasible to find any two different inputs m1 and m2 that produce the same hash. Note the distinction from second pre-image resistance: here, the attacker gets to choose both inputs freely.
SHA-256 satisfies all four of these properties with currently no known practical attacks on any of them.
SHA-256 is a member of the Merkle-Damgard construction family. Here is a simplified overview of the algorithm:
The input message is padded to ensure its length is congruent to 448 bits modulo 512 bits. Padding always begins with a 1 bit, followed by enough 0 bits, followed by a 64-bit representation of the original message length in bits.
The padded message is divided into 512-bit (64-byte) blocks. SHA-256 processes one block at a time.
SHA-256 begins with eight 32-bit words H0 through H7, derived from the fractional parts of the square roots of the first eight prime numbers. These are the initial hash values.
For each 512-bit block, SHA-256 runs 64 rounds of a compression function. Each round uses:
After processing all blocks, the eight 32-bit working variables are concatenated to produce the 256-bit final hash.
The use of modular arithmetic, bit rotations, and non-linear operations throughout ensures that the output is extremely sensitive to any change in the input.
Git uses SHA-1 for legacy reasons, but GitHub and other modern Git implementations are migrating to SHA-256. Every commit, tree, and blob object in a Git repository is identified by its hash. If even a single byte of a commit object changes, the hash changes — making it impossible to silently tamper with history.
git log --format="%H %s" -5
# a3f1c2... Add user authentication
# b89d40... Fix login redirect bug
When you download software, the provider often publishes a SHA-256 checksum alongside the file. After downloading, you compute the SHA-256 of the downloaded file and compare it to the published value. If they match, the file was not tampered with in transit.
sha256sum ubuntu-24.04.1-desktop-amd64.iso
# Compare output to the official checksum
Modern TLS certificates use SHA-256 as the signature algorithm (often written as "sha256WithRSAEncryption" or "ecdsa-with-SHA256"). When your browser connects to an HTTPS website, it verifies the server's certificate signature, which involves SHA-256 hashing.
Bitcoin uses double SHA-256 (SHA-256 applied twice) for:
SHA-256 is used as the underlying hash function in HMAC (Hash-based Message Authentication Code), a standard algorithm for verifying both the integrity and authenticity of messages. HMAC-SHA-256 is widely used in API authentication (AWS Signature Version 4, JWT HS256, webhook signatures, etc.).
Despite being a strong cryptographic hash, SHA-256 is not appropriate for hashing passwords. The problem is that SHA-256 is designed to be fast — it can process billions of hashes per second on modern hardware. This makes brute-force and dictionary attacks against password hashes feasible.
Password hashing requires slow, memory-hard functions like bcrypt, scrypt, or Argon2. These are specifically designed to make brute-force attacks expensive even with specialized hardware.
| Algorithm | Output size | Status | Notes |
|---|---|---|---|
| MD5 | 128 bits | Broken | Collision attacks published 1996; do not use for security |
| SHA-1 | 160 bits | Broken | Collision attack demonstrated 2017 (SHAttered); deprecated |
| SHA-256 | 256 bits | Secure | Current standard; no known practical attacks |
| SHA-3-256 | 256 bits | Secure | Different internal design (Keccak sponge); alternative to SHA-256 |
For new systems, always prefer SHA-256 or higher. MD5 and SHA-1 are acceptable only for non-security purposes like checksums where collision attacks are not a concern (though SHA-256 is fast enough that there is little reason to choose MD5 or SHA-1 even then).
// Using the Web Crypto API (works in browsers and modern Node.js)
async function sha256(message) {
const encoder = new TextEncoder()
const data = encoder.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("")
}
const hash = await sha256("hello")
console.log(hash)
// => 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
import hashlib
message = "hello"
hash_value = hashlib.sha256(message.encode()).hexdigest()
print(hash_value)
# => 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
import (
"crypto/sha256"
"fmt"
)
sum := sha256.Sum256([]byte("hello"))
fmt.Printf("%x\n", sum)
# macOS
echo -n "hello" | shasum -a 256
# Linux
echo -n "hello" | sha256sum
SHA-256 outputs a sequence of 32 bytes. These are most commonly displayed as:
Always be explicit about the format when communicating hash values. "SHA-256" alone does not specify whether the value is hex or Base64 encoded.
Whether you need to verify a file checksum, debug an HMAC signature, or explore how SHA-256 handles different inputs, the SHA-256 Generator on utils.live computes the hash of any text instantly in your browser — no data is sent to a server.
Free, browser-based tools — no sign-up required, your data never leaves your device.