The idea: many rounds of simple steps

AES and SHA-256 look like magic from outside, but inside they are short loops of very simple operations: table lookups, rotations, XORs and additions. One round of either is weak. Many rounds in a row mix every input bit into every output bit. The page runs both on the official test vectors, so every value you see can be checked against the standards.

Left, AES-128: the 16-byte plaintext and the key go into AddRoundKey with k0, then 10 rounds of SubBytes, ShiftRows, MixColumns and AddRoundKey (the last round without MixColumns) give the ciphertext; a key schedule makes the round keys k1 to k10. Right, SHA-256: the message is padded into a 512-bit block, expanded into 64 words W0 to W63, 64 rounds update the registers a to h, and adding them to H0 to H7 gives the 256-bit digest.
AES is a keyed, reversible permutation of 128 bits; SHA-256 is a keyless compression function that squeezes a 512-bit block into 256 bits.

The difference in purpose is in the shape. AES has a key and every step can be undone, so the receiver with the key can decrypt. SHA-256 has no key and throws information away (512 bits in, 256 out), so there is no way back. See Encryption vs Hashing for what each one is used for.

AES: the 4 × 4 byte state

AES-128 encrypts one 16-byte block at a time with a 16-byte key. The block is written into a 4 × 4 grid of bytes, the state, column by column: bytes 0–3 are column 0, bytes 4–7 column 1, and so on. The page uses the test vector from FIPS-197 Appendix C.1: plaintext 00112233445566778899aabbccddeeff, key 000102030405060708090a0b0c0d0e0f.

Round 0 is only AddRoundKey with k0, the key itself. Then come 10 rounds of four steps (Demo AES: key + round 1 in detail):

StepWhat it doesRound 1 of the test vector
SubBytesReplaces each byte through the S-box, a fixed 256-entry table (the inverse in GF(28), then an affine bit mix). The only non-linear step.00102030… → 63cab704…
ShiftRowsRotates row 1 one byte left, row 2 two bytes, row 3 three bytes. Each column now holds bytes from four different columns.→ 6353e08c…
MixColumnsMultiplies each column by a fixed 4 × 4 matrix over GF(28), so each output byte depends on all four bytes of its column.→ 5f726415…
AddRoundKeyXORs the state with the round key.⊕ d6aa74fd… → 89d810e8…

ShiftRows spreads bytes across columns and MixColumns spreads them within a column. Two rounds are enough for one input byte to reach all 16 bytes. The last round leaves MixColumns out (Demo AES: last round, no MixColumns). After round 10 the state is the ciphertext 69c4e0d86a7b0430d8cdb78070b4c55a (Demo AES: all 10 rounds). You can check it with echo 00112233445566778899aabbccddeeff | xxd -r -p | openssl enc -aes-128-ecb -K 000102030405060708090a0b0c0d0e0f -nopad | xxd -p.

The key schedule

The 16-byte key is stretched into 11 round keys k0…k10 of four 32-bit words each. To start kr, take the last word of kr−1, rotate it one byte (RotWord), run each byte through the S-box (SubWord), XOR a round constant Rcon (01, 02, 04, … 1b, 36) and XOR the first word of kr−1. Every other word is the word before it XOR the same word of kr−1. For round 1: 0c0d0e0f → 0d0e0f0c → d7ab76fe → ⊕ 01 → ⊕ 00010203 = d6aa74fd. The round log on the right of the canvas lists all 11 keys.

Decryption runs the inverse steps (InvSubBytes, InvShiftRows, InvMixColumns) with the round keys in reverse order. AES-192 and AES-256 use the same round, with 12 and 14 rounds.

SHA-256: padding and the message schedule

SHA-256 works on 512-bit blocks of sixteen 32-bit words. The message "abc" is 3 bytes, 61 62 63. Padding appends one 1 bit (the byte 80), zeros, and the message length in bits as a 64-bit number (24 = 0x18), so W0 = 61626380, W1…W14 = 0 and W15 = 00000018. A longer message gives several blocks, each run through the same compression function.

The message schedule expands the 16 words into 64, one per round: W[t] = σ1(W[t−2]) + W[t−7] + σ0(W[t−15]) + W[t−16], where σ0 and σ1 XOR together rotations and a shift of a word (Demo SHA: padding + message schedule). All additions are mod 232.

SHA-256: 64 rounds on a..h

Eight 32-bit working registers a…h start with H0…H7 (the first 32 bits of the fractional parts of √2, √3, √5 … √19). Each round t computes two temporary words and shifts the registers by one place:

  • T1 = h + Σ1(e) + Ch(e, f, g) + K[t] + W[t]. Ch (choose) takes each bit from f where e is 1 and from g where e is 0. K[t] is a fixed constant from the cube root of the t-th prime.
  • T2 = Σ0(a) + Maj(a, b, c). Maj (majority) gives each bit the value that at least two of a, b, c have.
  • h = g, g = f, f = e, e = d + T1, d = c, c = b, b = a, a = T1 + T2.
One SHA-256 round: the eight registers a to h in a row. T1 is computed from e, f, g, h, K[t] and W[t]; T2 from a, b and c. Every register shifts one place to the right and h drops out; the new a is T1 plus T2 and the new e is d plus T1. Round 0 of abc: a becomes 5d6aebcd and e becomes fa2a4622.
Each round only computes two new words, a and e; the other six registers just move one place right.

After round 63 each register is added to its H word: H0 + a, …, H7 + h (the final add, also called the Davies–Meyer feed-forward). Without it, anyone who picks the message words could run the rounds backwards from a wanted output; adding the starting H back in blocks that. H0…H7 written one after another is the digest: SHA-256("abc") = ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad (Demo SHA: the whole hash of "abc"), as printf abc | shasum -a 256 prints.

The avalanche effect

A good cipher or hash changes about half of the output bits when a single input bit changes, and which bits change looks random. Press Flip 1 Bit: AES encrypts a second plaintext whose byte 0 is 01 instead of 00. The two states differ in 1 bit after round 0, in 17 bits after round 1 (MixColumns spread the changed byte over one column) and in 64 bits after round 2. The ciphertexts differ in 62 of 128 bits (Demo AES: avalanche). For SHA-256, "abb" differs from "abc" in one bit, and the digests differ in 124 of 256 bits (Demo SHA: avalanche).

Bar chart of how many of the 128 AES state bits differ after each round when one plaintext bit is flipped: 1 after round 0, 17 after round 1, 64 after round 2, then between 58 and 71 for rounds 3 to 10, ending at 62. A dashed line marks 64, half of the bits.
One flipped bit reaches about half of the 128 state bits after only two AES rounds; the other eight rounds are a safety margin.

Compare a CRC: it is linear, so one flipped bit changes the CRC in a fixed, predictable way, and anyone can fix up the checksum. A CRC catches accidents, not attackers.

AES vs SHA-256

AES-128SHA-256
KindBlock cipher (keyed permutation)Hash function (keyless compression)
Input per call128-bit block + 128-bit key512-bit block + 256-bit chaining value H
Output128-bit ciphertext, reversible with the key256-bit digest, not reversible
Rounds10 (+ initial AddRoundKey)64
Word sizeBytes, GF(28) arithmetic32-bit words, + mod 232, rotations, XOR
Non-linear partS-boxCh, Maj and carries of the additions
ExpansionKey schedule: 16 bytes → 11 round keysMessage schedule: 16 words → 64
Used inTLS (AES-GCM), disk encryption, Wi-Fi WPA2/3TLS, signatures, Git, Bitcoin, HMAC, password hashing inside PBKDF2

See also Symmetric vs Asymmetric Encryption (where AES fits in TLS), How a Digital Signature Works (which signs a SHA-256 digest) and Salt vs Pepper (why a plain fast SHA-256 is not enough for passwords).

SHA-256 as a mining puzzle (find a nonce so the hash is below a target) is on Proof of Work.

What the page leaves out

Modes of operation: AES alone encrypts one 16-byte block; real systems use a mode such as GCM or CTR with a nonce, never ECB for more than one block. Decryption and the inverse steps; AES-192 and AES-256; the S-box and MixColumns arithmetic in GF(28) beyond one worked byte; hardware AES instructions (AES-NI) and table-based implementations; side-channel attacks. For SHA-256: messages longer than one block (the H words chain from block to block), the length-extension property that HMAC works around, SHA-224/384/512 and SHA-3, and the details of every constant.