Learn · Technologies we use
How SHA-256 works, step by step
The standard's "abc" example worked through padding, the message schedule and the 64 rounds, with an explorer you can run on your own text.
SHA-256 turns any message into a 256-bit fingerprint. It reads the message in 64-byte blocks, mixes each block into a state of eight 32-bit words with 64 rounds of simple operations (add, rotate, XOR and a few bit-selection functions), and prints the final state. The same message always gives the same fingerprint, and changing one bit anywhere gives one that looks unrelated. We'll follow the standard's own three-byte example, abc, through every stage, using code on this site that's checked against the standard and against Node's crypto. The tool below is that code, so type your own message and watch it run.
1. Padding: the block that is actually hashed
Your bytes the 1 bit zeros the length in bits
2. The message schedule: 64 words from 16
3. The 64 rounds
4. The avalanche
Nothing you type here leaves your browser.
Where it comes from
SHA-256 belongs to the SHA-2 family, which the US National Security Agency designed and first published in 2001. NIST standardized it as FIPS 180-2 in 2002, and today FIPS 180-4 (2012) specifies it. The family has six members with 224-, 256-, 384- and 512-bit outputs. SHA-224 and SHA-256 work on 32-bit words and 64-byte blocks, and SHA-384 and SHA-512 on 64-bit words and 128-byte blocks. SHA-256 is the one in TLS certificates, in Bitcoin's proof of work, in file checksums and, in this site's code, inside PBKDF2. The properties a hash must have, and how MD5 and SHA-1 lost them, are in What a hash function is.
Step 1: padding
The compression function takes exactly 64 bytes at a time, so the message gets padded to a multiple of 64 bytes: a single 1 bit first, then as many 0 bits as it takes, and in the last 8 bytes the length of the original message in bits. For abc the three bytes are 61 62 63, and the padded block is:
61626380 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000018
The byte after 63 is 80, which is the 1 bit followed by seven zeros. The last word is 18 in hexadecimal, 24 in decimal, the message's 3 bytes counted as 24 bits. A message of 56 bytes or more leaves no room for the length in one block, so it pads to two. The length goes in so that no two different messages can ever pad to the same sequence of blocks.
Step 2: the message schedule
The block's 16 words get stretched into 64. Each new word is built from four earlier ones: W[i] = W[i−16] + σ0(W[i−15]) + W[i−7] + σ1(W[i−2]), with addition modulo 232. Here σ0(x) is x rotated right by 7, XOR x rotated right by 18, XOR x shifted right by 3, and σ1(x) is the same with 17, 19 and 10. You can check the first new word by hand. Almost all of the block is zero, so W[16] is just W[0], 61626380. The next one, W[17], comes entirely from σ1 of the length word 00000018. That word rotated right by 17 is 000c0000, rotated right by 19 is 00030000, and shifted right by 10 is zero, and the XOR of the three is 000f0000, which is what the explorer shows. After a few words every position depends on the message, and by W[63] (12b1edeb here) the single block has been mixed through the whole schedule.
Step 3: the 64 rounds
The state is eight words, a to h, starting from eight constants. They're the first 32 bits of the fractional parts of the square roots of the first eight primes (a starts at 6a09e667, from √2). Each round also uses a constant Kt, the first 32 bits of the fractional part of the cube root of the t-th prime (428a2f98 from ∛2 for round 0, and c67178f2 in round 63). They come from primes by a public rule, so nobody can suspect they were picked to hide a weakness. The code on this page computes them, and a test checks that they equal the standard's. A round does this:
T1 = h + Σ1(e) + Ch(e, f, g) + K[t] + W[t] T2 = Σ0(a) + Maj(a, b, c) h = g; g = f; f = e; e = d + T1 d = c; c = b; b = a; a = T1 + T2
Ch(e, f, g) means "for each bit, take f where e is 1 and g where it's 0". Maj is the bitwise majority vote of three words. Σ1(e) is e rotated right by 6, 11 and 25 and XORed, and Σ0(a) is a rotated right by 2, 13 and 22 and XORed. Round 0 of abc works out as Σ1(e) = 3587272b, Ch = 1f85c98c, Σ0(a) = ce20b47e and Maj = 3a6fe667, so T1 = 5be0cd19 + 3587272b + 1f85c98c + 428a2f98 + 61626380 = 54da50e8 and T2 = 08909ae5. The new state begins 5d6aebcd 6a09e667 bb67ae85 3c6ef372 fa2a4622 …. Only a and e are new, and the other six words just slide one place along.
The only nonlinear parts are the additions (carries ripple between bits) plus Ch and Maj. Rotations and XOR are linear, so no single round hides anything, which is why the design uses 64 of them.
Step 4: adding back
After round 63 the state is 506e3058 d39a2165 04d24d6c b85e2ce9 5ef50f24 fb121210 948d25b6 961f4894. Add it word by word, modulo 232, to the state from before the block (here, the eight starting constants), and the sum is the output: ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad, the digest in the standard. The addition is what makes the function one-way, since without it you could run the 64 rounds backwards. If there's a second block, this sum becomes its starting state.
The avalanche
Change the first byte of abc by one bit (a is 61, ` is 60) and count how many of the 256 state bits differ after each round. The first rounds give 3, 23, 48, 80, 109, 120 and then 135, and from there the count stays near 128 for the remaining rounds, because about half the bits differ between two unrelated values. The final digests differ in 112 of 256 bits: 89f90039 0e14d37c … instead of ba7816bf 8f01cfea …. That's the avalanche effect. It's why nobody can find a message whose hash is close to a given hash, or take a small step from one message to another with a related fingerprint.
How strong is it?
- Collisions. Because of the birthday effect, any 256-bit hash has a generic collision cost of about 2128 hashes, which is out of reach. Nobody has published an attack on the full 64 rounds that beats that. Attacks on reduced-round versions exist and are the normal way a design gets studied. SHA-256 has been in wide use since the early 2000s without a practical break, unlike MD5 and SHA-1.
- Preimages. Finding a message for a given hash costs about 2256 by brute force.
- Length extension. SHA-256's output is the whole internal state, so anyone who knows H(m) can compute the hash of m, the padding and a suffix of their choice, without knowing m. That's why
SHA-256(key + message)makes an unsafe MAC, and it's what HMAC is for. SHA-512/256 and SHA-3 avoid it by design. - Passwords. It's fast, the opposite of what a password hash needs (bcrypt, scrypt, Argon2 and PBKDF2).
How cipher.ink uses this
SHA-256 does three jobs here. Inside PBKDF2-HMAC-SHA256 it's the hash run 600,000 times to turn a passphrase into a key. When you seal a message, the page sends the server only the SHA-256 of the receipt token, never the token itself, and a later request to burn the message or count a read has to present a token that hashes to the stored value (read receipts without tracking). And the server hashes an IP address with SHA-256 to rate-limit, so it never stores the address itself. The code for the first two is a few lines of crypto.js, and the browser's own Web Crypto does the hashing (the Web Crypto API).