krishworkstech.com

How Does the AES Encryption Algorithm Protect Your Data?

A walk through the AES block cipher for readers who know what addition and multiplication are, but who have never had cryptography patiently explained to them. By the end you will know exactly what AES does to your bytes, and why the result is hard to undo without the key.

The technology behind secure data; and why encryption is essential for connected products.

Published: July 22, 2026

AES Encryption

AES Encryption at a Glance

Sensitive data is vulnerable when stored, shared, or transmitted across systems.

AES uses a shared secret key and multiple rounds of mathematical transformations to scramble data into an unreadable format.

Attackers who intercept the data see only encrypted ciphertext, not the original information.

Strong encryption + secure key management = protection for data at rest and in transit.

TABLE OF CONTENTS

WRITTEN BY

Subhajit Roy

Subhajit Roy

Co-Founder & Embedded Engineer

Krishworks Technology Innovations

01

What we are trying to build

Forget cryptography for a moment. Here is a puzzle.

You and a friend want a machine that takes any 16 bytes of input and produces 16 bytes of output, like this:

16 bytes in (plaintext) machine (the cipher) 16 bytes out (ciphertext) 16-byte secret key

You both share a secret — a 16-byte key that you and only you know. The machine has the following properties:

It is reversible if you have the key.

Feed the output back in with the same key (running the machine in reverse) and you get the original 16 bytes back.

It is not reversible without the key.

Someone who sees a million (input, output) pairs but doesn’t know the key cannot figure the key out, no matter how clever they are or how much computer time they have.

It “looks random.”

If you flip a single bit of the input or the key, roughly half the output bits change. There is no visible pattern relating inputs to outputs.

A machine that does all three things is called a block cipher. The specific block cipher we are going to build up to is called AES — the Advanced Encryption Standard, designed in the late 1990s and adopted by the US government in 2001. It is, by a comfortable margin, the most widely deployed cipher on earth. Every TLS connection your browser opens, every encrypted Wi-Fi packet, every iPhone disk, every   LoRa payload in the sister article — all are AES at the bottom.

The plan for this document: spend the first few sections on prerequisites, then introduce AES’s four basic operations one at a time, then put them together into the full algorithm, then walk through a concrete numerical example so you can see every byte change. You won’t need any maths beyond grade-school arithmetic and a little patience.

02

Prerequisites: bytes, hex, and XOR

Bytes

A byte is 8 bits. Each bit is 0 or 1, so a byte can hold any of 2⁸ = 256 different values, from 0 to 255. We will write bytes in hexadecimal because it is more compact than binary and aligns nicely with the structure of AES.

Hexadecimal uses 16 digits: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. Each hex digit represents 4 bits (half a byte), so any byte fits in exactly two hex digits.

Decimal Binary Hex
0 0000 0000 00
1 0000 0001 01
10 0000 1010 0A
15 0000 1111 0F
16 0001 0000 10
100 0110 0100 64
255 1111 1111 FF

If you have not used hex before: it is just a different way of writing the same numbers. 0x4C means the value 76 in decimal, which is 01001100 in binary. They are all the same byte.

A 16-byte block, written in hex with spaces between bytes, looks like:

48 65 6C 6C 6F 2C 20 41 45 53 20 77 6F 72 6C 64

(That happens to be the ASCII for “Hello, AES world”.)

XOR — the one operation you need to be comfortable with

The whole of AES uses only three kinds of byte-level operation: lookup in a table, rearranging bytes, and XOR. We are about to lean on XOR heavily, so let us get familiar with it.

XOR stands for “exclusive or.” It is an operation that takes two bits and gives back one bit, with this truth table:

A B A ⊕ B
0 0 0
0 1 1
1 0 1
1 1 0

In words: the result is 1 if the two inputs are different, and 0 if they are the same.

For two whole bytes, we XOR each pair of bits independently:

     0x4C  =  0 1 0 0 1 1 0 0
     0xA9  =  1 0 1 0 1 0 0 1
     ─────────────────────────  ⊕
     0xE5  =  1 1 1 0 0 1 0 1

The only fact about XOR you really need to remember is its self-inverse property:

   A ⊕ B ⊕ B  =  A

If you XOR a value with anything, then XOR with the same thing again, you get the original value back. This is what makes XOR-based ciphers reversible: encrypting and decrypting are literally the same operation.

Try it: take any byte X, XOR with 0xA5, and then XOR the result with 0xA5 again. You will land back on X every time.

A first cipher made of nothing but XOR

The simplest cipher in the world is: take your message, XOR each byte with a corresponding byte of the secret key, send the result. To decrypt, the recipient XORs again with the same key.

   plaintext  P = 48 65 6C 6C 6F ...
   key        K = A1 B2 C3 D4 E5 ...
                  ──────────────── ⊕
   ciphertext C = E9 D7 AF B8 8A ...

If the key is truly random, never reused, and as long as the plaintext, this is a one-time pad — provably unbreakable. The catch is that you need a fresh chunk of random key for every byte of data you ever encrypt, and that is impractical in any real system. Reuse the key even slightly, and the cipher falls apart.

So we want a way to take a short, fixed-size key and use it to generate as much pseudo-random output as we like — and to do that in a way that depends so intricately on the input that an attacker cannot recover the key from the output. That is the gap AES fills.

Building a secure IoT product that protects sensitive data?

Krishworks secures connected devices with strong encryption.

03

Why simple ideas don't work

It is worth seeing why a few obvious approaches fail, because each failure motivates one piece of AES’s design.

Idea: a substitution cipher

A concrete example. Suppose we use this tiny substitution table for the 26 capital letters (the rest map to themselves):

   plain :   A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
   cipher:   Q W E R T Y U I O P A S D F G H J K L Z X C V B N M

Encrypt the message HELLO WORLD :

   H → I        W → V
   E → T        O → G
   L → S        R → K
   L → S        L → S
   O → G        D → R

   HELLO WORLD  →  ITSSG VGKSR

Idea: a permutation cipher

A concrete example. Take the 16-byte block:

   position:    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
   byte:        H  E  L  L  O  _  A  E  S  _  W  O  R  L  D  !

(Treating _ as space.) Now permute positions: send byte 0 to position 7, byte 1 to position 12, byte 2 to position 3, and so on through some fixed scrambling table. The output is some shuffled version like:

   E  W  L  L  R  _  !  H  S  A  D  E  O  L  O  _

Idea: mix bytes together with arithmetic

If byte 0 of the output is some combination of bytes 0, 1, 2, 3 of the input, then changing input byte 1 changes output byte 0. That is called diffusion: each output bit comes to depend on many input bits. AES uses a diffusion step called MixColumns.

A concrete example. Suppose we define a “mixing” step like this:

   new[0] = (old[0] + old[1] + old[2] + old[3]) mod 256
   new[1] = (         old[1] + old[2] + old[3]) mod 256
   new[2] = (                  old[2] + old[3]) mod 256
   new[3] =                              old[3]

This looks like it does something — each output byte depends on several input bytes. And it is invertible: we can recover the inputs from the outputs by working from the bottom up (old[3] = new[3], then old[2] = new[2] − old[3], and so on). Try it with input (10, 20, 30, 40):

   new[0] = 10 + 20 + 30 + 40 = 100
   new[1] =      20 + 30 + 40 =  90
   new[2] =           30 + 40 =  70
   new[3] =                40 =  40

Idea: XOR a key into the mix at every stage

Every operation so far has been fixed — the same table, the same shuffle, the same mixing formula no matter what the key is. That is no good; the cipher needs to depend on the secret key. AES sprinkles the key in by XORing it into the state at every round. This step is called AddRoundKey.

A concrete example: why repeating a key is catastrophic. Suppose we naively encrypt by XOR alone, and we encrypt two different messages with the same 8-byte key:

   P₁ = "HELLO!!!"        K = "SeCrEt99"        C₁ = P₁ ⊕ K
   P₂ = "WORLD!!!"        same K                C₂ = P₂ ⊕ K

The attacker captures both ciphertexts (they were sent over the air). They compute:

   C₁ ⊕ C₂  =  (P₁ ⊕ K) ⊕ (P₂ ⊕ K)
            =   P₁ ⊕ P₂ ⊕ K ⊕ K
            =   P₁ ⊕ P₂ ⊕ 0
            =   P₁ ⊕ P₂

Idea: do it once, you're done

04

The state: a 4×4 grid of bytes

AES does not operate on the 16 bytes as a flat row. It arranges them into a 4×4 grid, called the state. Bytes are filled in column by column from the input:

Input: 16 bytes in a row b₀ b₁ b₂ b₃ b₄ b₅ b₆ b₇ b₈ b₉ b₁₀ b₁₁ b₁₂ b₁₃ b₁₄ b₁₅ become the 4×4 state, column by column b₀ b₄ b₈ b₁₂ b₁ b₅ b₉ b₁₃ b₂ b₆ b₁₀ b₁₄ b₃ b₇ b₁₁ b₁₅ col 0 col 1 col 2 col 3
Figure 1. Sixteen input bytes laid out as a 4×4 state, column by column. Each colour group of four bytes forms one column of the state.

For example, the 16 input bytes 48 65 6C 6C 6F 2C 20 41 45 53 20 77 6F 72 6C 64 become the state:

   ┌────┬────┬────┬────┐
   │ 48 │ 6F │ 45 │ 6F │
   ├────┼────┼────┼────┤
   │ 65 │ 2C │ 53 │ 72 │
   ├────┼────┼────┼────┤
   │ 6C │ 20 │ 20 │ 6C │
   ├────┼────┼────┼────┤
   │ 6C │ 41 │ 77 │ 64 │
   └────┴────┴────┴────┘

Operation 1 — SubBytes (the nonlinear scrambler)

Here is what the first few entries look like:

input output
0x00 0x63
0x01 0x7C
0x02 0x77
0x48 0x52
0xFF 0x16
input byte 0x48 lookup S-box (256 entries) 00 → 63 01 → 7C ... 48 → 52 ... FF → 16 out 52
Figure 2. SubBytes is a 256-entry lookup table. Each byte of the state is replaced independently with whatever the table says.

Operation 2 — ShiftRows (move things around)

The second operation in each round is ShiftRows. It is exactly what it sounds like: each row of the 4×4 state is shifted left by a fixed number of positions, with the bytes that fall off the left edge wrapping around to the right.

before ShiftRows a₀ a₁ a₂ a₃ b₀ b₁ b₂ b₃ c₀ c₁ c₂ c₃ d₀ d₁ d₂ d₃ after ShiftRows a₀ a₁ a₂ a₃ b₁ b₂ b₃ b₀ c₂ c₃ c₀ c₁ d₃ d₀ d₁ d₂ row 0: no shift row 1: shift left 1 row 2: shift left 2 row 3: shift left 3 No values change — only positions. Bytes that fall off the left wrap around to the right.
Figure 3. ShiftRows. Each row is rotated left by row-index positions. Information now crosses column boundaries — essential for the next step.

Operation 3 — MixColumns (mix bytes within each column)

The third operation is MixColumns. This is where each output byte becomes a combination of several input bytes — the diffusion step.

For each column of the state, we replace the four bytes with four new bytes computed like this:

   new[0] = (2 · old[0]) ⊕ (3 · old[1]) ⊕  old[2]     ⊕  old[3]
   new[1] =  old[0]      ⊕ (2 · old[1]) ⊕ (3 · old[2]) ⊕  old[3]
   new[2] =  old[0]      ⊕  old[1]      ⊕ (2 · old[2]) ⊕ (3 · old[3])
   new[3] = (3 · old[0]) ⊕  old[1]      ⊕  old[2]     ⊕ (2 · old[3])

The ⊕ is just XOR, which we know. The question is: what does 2 · x mean when x is a byte?

It is almost normal multiplication, with one twist. The rule is:

“2 · x”: shift x one bit to the left. If the bit that fell off the top was 1, then XOR the result with 0x1B.

That’s it. Let’s try a couple of examples.

  • 0x57 in binary is 0101 0111.
  • Shift left by 1: 1010 1110 = 0xAE. The bit that fell off the top was 0.
  • No further adjustment needed.
  • Answer: 2 · 0x57 = 0xAE.
  • 0x83 in binary is 1000 0011.
  • Shift left by 1: 0000 0110 = 0x06. The bit that fell off the top was 1.
  • Because that bit was 1, XOR with 0x1B: 0x06 ⊕ 0x1B = 0x1D.
  • Answer: 2 · 0x83 = 0x1D.

    The 3 · x is even easier: just compute 2 · x and then XOR with the original x. (Because 3 = 2 + 1 and in this strange arithmetic addition is XOR.)

  • 2 · 0x57 = 0xAE (from above).
  • 3 · 0x57 = 0xAE ⊕ 0x57 = 0xF9.

Why this weird multiplication? Because we want our “multiplication” to keep results inside the set of bytes (0–255). Normal multiplication would produce values larger than 255 — multiplying two bytes can give you up to 0xFE01. The shift-and-conditional-XOR rule keeps everything inside the byte range while still acting enough like multiplication that the four MixColumns formulas above have all the nice algebraic properties they need to be invertible.

If you’ve heard of “Galois field arithmetic” or “GF(2⁸)”, that’s the formal name for this kind of arithmetic. You do not need to learn the theory to use it; the rules above are everything you need to implement MixColumns correctly.

Why does MixColumns matter?

Operation 4 — AddRoundKey (mix the secret in)

The fourth and final operation in each round is AddRoundKey. It is the simplest of the four: take the current state and XOR it with a 16-byte round key, byte by byte.

s₀ s₄ s₈ s₁₂ s₁ s₅ s₉ s₁₃ s₂ s₆ s₁₀ s₁₄ s₃ s₇ s₁₁ s₁₅ state k₀ k₄ k₈ k₁₂ k₁ k₅ k₉ k₁₃ k₂ k₆ k₁₀ k₁₄ k₃ k₇ k₁₁ k₁₅ round key = s₀⊕k₀ s₄⊕k₄ s₈⊕k₈ s₁₂⊕k₁₂ s₁⊕k₁ s₅⊕k₅ s₉⊕k₉ s₁₃⊕k₁₃ s₂⊕k₂ s₆⊕k₆ s₁₀⊕k₁₀ s₁₄⊕k₁₄ s₃⊕k₃ s₇⊕k₇ s₁₁⊕k₁₁ s₁₅⊕k₁₅ new state
Figure 4. AddRoundKey. The state and the round key are XORed byte by byte, in place. This is the only step that actually depends on the secret key.

This is where the secret key actually enters the calculation. Without AddRoundKey, AES would be a completely fixed, deterministic scrambling function — the same input would always give the same output. AddRoundKey is what makes the output depend on the key, and because XOR is the self-inverse operation we met earlier, it is also the only operation that absolutely has to use the key (the other three operations use no secrets — they are public).

Now: where do round keys come from?

Need stronger data security for your IoT application?

Let’s build secure, encrypted systems designed to protect your data.

05

Key expansion : from one key to eleven

AES-128 has 10 rounds. Each round needs a 16-byte round key, and there is also one extra AddRoundKey before the first round. So we need 11 round keys, total 176 bytes, derived from your single 16-byte secret key.

The procedure is called key expansion, or the key schedule. The full rules are slightly fiddly, but the idea is straightforward:

The extra twist every fourth word is what stops the key schedule being a simple linear function of the key. Without it, an attacker who recovered any round key could trivially derive the original. With it, round keys look unrelated to the original even though they’re deterministically computed from it.

You almost never need to understand the key schedule in detail to use AES; libraries do it for you. But it is worth knowing it exists, because it explains the otherwise-mysterious fact that “AES-128 has a 128-bit key but uses 11 different 128-bit keys internally.”

The full algorithm, assembled

We now have all the pieces. The full AES-128 encryption procedure is:

Plaintext (16 bytes) AddRoundKey with K₀ Rounds 1 — 9 (each identical) SubBytes ShiftRows MixColumns AddRoundKey with K₁ … K₉ Round 10 (final — no MixColumns) SubBytes ShiftRows AddRoundKey with K₁₀ Ciphertext (16 bytes)
Figure 5. AES-128 in full. An initial AddRoundKey, nine identical rounds, and one final round that skips MixColumns. Eleven round keys total, all derived from the single 16-byte secret key.

A few observations.

A concrete trace: encrypting one block

Let’s make it real. We’ll use a well-known test vector from the AES specification, so you can reproduce it with any AES library and check your understanding.

The inputs.

   Plaintext (16 bytes):  00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
   Key       (16 bytes):  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

Step 1 — load into the state, column by column.

   ┌────┬────┬────┬────┐
   │ 00 │ 44 │ 88 │ CC │
   ├────┼────┼────┼────┤
   │ 11 │ 55 │ 99 │ DD │
   ├────┼────┼────┼────┤
   │ 22 │ 66 │ AA │ EE │
   ├────┼────┼────┼────┤
   │ 33 │ 77 │ BB │ FF │
   └────┴────┴────┴────┘

Step 2 — AddRoundKey with K₀ (the original key).

K₀ is just the input key, loaded the same way:

Check one: 0x11 ⊕ 0x01 = 0x10 ✓. 0xCC ⊕ 0x0C = 0xC0 ✓.

Step 3 — round 1, SubBytes.


                       state                    K₀                  state ⊕ K₀

                ┌────┬────┬────┬────┐    ┌────┬────┬────┬────┐    ┌────┬────┬────┬────┐
                │ 00 │ 44 │ 88 │ CC │    │ 00 │ 04 │ 08 │ 0C │    │ 00 │ 40 │ 80 │ C0 │
                ├────┼────┼────┼────┤    ├────┼────┼────┼────┤    ├────┼────┼────┼────┤
                │ 11 │ 55 │ 99 │ DD │    │ 01 │ 05 │ 09 │ 0D │    │ 10 │ 50 │ 90 │ D0 │
                ├────┼────┼────┼────┤ ⊕   ───┼────┼────┼────┤  = ├────┼────┼────┼────┤
                │ 22 │ 66 │ AA │ EE │    │ 02 │ 06 │ 0A │ 0E │    │ 20 │ 60 │ A0 │ E0 │
                ├────┼────┼────┼────┤    ├────┼────┼────┼────┤    ├────┼────┼────┼────┤
                │ 33 │ 77 │ BB │ FF │    │ 03 │ 07 │ 0B │ 0F │    │ 30 │ 70 │ B0 │ F0 │
                └────┴────┴────┴────┘    └────┴────┴────┴────┘    └────┴────┴────┴────┘

Look up every byte in the AES S-box:

                state                                S-box(state)
         ┌────┬────┬────┬────┐                ┌────┬────┬────┬────┐
         │ 00 │ 40 │ 80 │ C0 │                │ 63 │ 09 │ CD │ BA │
         ├────┼────┼────┼────┤                ├────┼────┼────┼────┤
         │ 10 │ 50 │ 90 │ D0 │       ───►     │ CA │ 53 │ 60 │ 70 │
         ├────┼────┼────┼────┤                ├────┼────┼────┼────┤
         │ 20 │ 60 │ A0 │ E0 │                │ B7 │ D0 │ E0 │ E1 │
         ├────┼────┼────┼────┤                ├────┼────┼────┼────┤
         │ 30 │ 70 │ B0 │ F0 │                │ 04 │ 51 │ E7 │ 8C │
         └────┴────┴────┴────┘                └────┴────┴────┴────┘

(If you want to verify a few: S-box[0x00] = 0x63, S-box[0x40] = 0x09, S-box[0xC0] = 0xBA. Any reference AES S-box table will confirm.)

Step 4 — round 1, ShiftRows.

Row 0 is unchanged; row 1 shifts left by 1; row 2 by 2; row 3 by 3.

   before ShiftRows:                 after ShiftRows:
   ┌────┬────┬────┬────┐             ┌────┬────┬────┬────┐
   │ 63 │ 09 │ CD │ BA │             │ 63 │ 09 │ CD │ BA │   row 0, no shift
   ├────┼────┼────┼────┤             ├────┼────┼────┼────┤
   │ CA │ 53 │ 60 │ 70 │     ───►    │ 53 │ 60 │ 70 │ CA │   row 1, left 1
   ├────┼────┼────┼────┤             ├────┼────┼────┼────┤
   │ B7 │ D0 │ E0 │ E1 │             │ E0 │ E1 │ B7 │ D0 │   row 2, left 2
   ├────┼────┼────┼────┤             ├────┼────┼────┼────┤
   │ 04 │ 51 │ E7 │ 8C │             │ 8C │ 04 │ 51 │ E7 │   row 3, left 3
   └────┴────┴────┴────┘             └────┴────┴────┴────┘

Step 5 — round 1, MixColumns.

For each column, apply the four formulas from §7. Let us compute one column in full — the first one, with bytes 63, 53, E0, 8C.

   new[0] = 2·63 ⊕ 3·53 ⊕ E0 ⊕ 8C
   new[1] =   63 ⊕ 2·53 ⊕ 3·E0 ⊕ 8C
   new[2] =   63 ⊕ 53 ⊕ 2·E0 ⊕ 3·8C
   new[3] = 3·63 ⊕ 53 ⊕ E0 ⊕ 2·8C

Compute the “doublings” we need:

And the “triples” (each is “double” XOR original):

Now plug in:

   new[0] = 2·63 ⊕ 3·53 ⊕ E0 ⊕ 8C
          = C6   ⊕ F5   ⊕ E0 ⊕ 8C
          = (C6 ⊕ F5) ⊕ (E0 ⊕ 8C)
          = 33        ⊕ 6C
          = 5F

   new[1] = 63 ⊕ 2·53 ⊕ 3·E0 ⊕ 8C
          = 63 ⊕ A6   ⊕ 3B   ⊕ 8C
          = (63 ⊕ A6) ⊕ (3B ⊕ 8C)
          = C5        ⊕ B7
          = 72

   new[2] = 63 ⊕ 53 ⊕ 2·E0 ⊕ 3·8C
          = 63 ⊕ 53 ⊕ DB   ⊕ 8F
          = (63 ⊕ 53) ⊕ (DB ⊕ 8F)
          = 30        ⊕ 54
          = 64

   new[3] = 3·63 ⊕ 53 ⊕ E0 ⊕ 2·8C
          = A5   ⊕ 53 ⊕ E0 ⊕ 03
          = (A5 ⊕ 53) ⊕ (E0 ⊕ 03)
          = F6        ⊕ E3
          = 15

So column 0 becomes (5F, 72, 64, 15). The same calculation repeated for columns 1, 2, 3 fills out the new state. You now have your first round’s MixColumns output.

Step 6 — round 1, AddRoundKey with K₁.

K₁ comes from the key schedule. The first round key after the original key works out to:

   K₁ = D6 AA 74 FD D2 AF 72 FA DA A6 78 F1 D6 AB 76 FE

(Verifiable against any AES reference implementation.)

You XOR the MixColumns output with K₁, and that gives you the state after round 1.

Steps 7 to 14 — rounds 2 through 9.

Exactly the same four operations: SubBytes, ShiftRows, MixColumns, AddRoundKey, each with the appropriate round key K₂, K₃, …, K₉.

Step 15 — round 10 (final round, no MixColumns).

SubBytes, ShiftRows, AddRoundKey with K₁₀.

Step 16 — read out the ciphertext.

After round 10, the state is read column-by-column as 16 bytes. For the specific inputs we used, the result is:

   Ciphertext: 69 C4 E0 D8 6A 7B 04 30 D8 CD B7 80 70 B4 C5 5A

This is the standard NIST test vector for AES-128. If you implement AES from this article and get the same 16 output bytes, your implementation is correct.

Decryption: reversing the gears

Each of the four operations has an inverse:

To decrypt, you run the rounds in reverse:

   AddRoundKey K₁₀
   InvShiftRows
   InvSubBytes

   AddRoundKey K₉
   InvMixColumns
   InvShiftRows
   InvSubBytes

   …  (rounds 8 down to 1, same pattern)

   AddRoundKey K₀

   Output: plaintext
06

What makes AES secure?

This is the deepest question and the one we can only answer informally without diving into cryptanalysis papers. Here is the intuition.

Confusion.

The relationship between the secret key and the ciphertext should be as complex as possible. SubBytes provides this: its nonlinearity means no neat algebraic expression connects key bits to ciphertext bits. An attacker cannot solve a system of equations to extract the key.

Diffusion.

Every bit of the ciphertext should depend on every bit of the plaintext and every bit of the key. ShiftRows and MixColumns together provide this: after two rounds, each output byte depends on all 16 input bytes; after ten rounds, the dependency is so thorough that statistical correlations are vanishingly small.

Avalanche.

Flipping one bit anywhere in the input or the key should change roughly half the output bits, in an unpredictable pattern. AES’s avalanche is excellent — measurable in the lab as about 64 bits of the 128-bit output changing on average per single-bit input change.

Resistance to known attacks..

The cipher was designed with specific cryptanalytic attacks in mind — differential cryptanalysis, linear cryptanalysis — and the S-box and MixColumns coefficients were chosen to maximise resistance to those attacks. After 25 years of intense public scrutiny, the best published attacks on full AES-128 are barely better than brute force.

Key length.

2¹²⁸ possible keys is roughly 3.4 × 10³⁸. If you could test a trillion keys per second on each of a trillion machines working in parallel, you’d still need over ten million years to exhaust the key space. AES-256 pushes this even further, primarily as a hedge against future quantum computers (which can effectively halve the key length via Grover’s algorithm; AES-256 against a quantum attacker has the same difficulty as AES-128 against a classical one).

The honest summary: AES is secure because after 25 years of thousands of cryptographers trying to break it, nobody has come even close. That kind of confidence is rare in cryptography. It is what justifies AES’s ubiquity.

07

What we glossed over

For honesty’s sake, things this article skipped or simplified:

The S-box construction.

We described the S-box as “a fixed table.” It is actually built from two steps: take the multiplicative inverse of the input byte in GF(2⁸), then apply a specific affine transformation. This construction is what gives the S-box its excellent cryptographic properties, but you do not need to understand it to use AES.

The MixColumns coefficients.

We used 1, 2, 3 as the multiplication constants. Those come from the polynomial 3x³ + x² + x + 2, chosen so that MixColumns is a “Maximum Distance Separable” transformation — the smallest possible change in input spreads to the largest possible change in output.

AES-192 and AES-256.

These variants use 24- and 32-byte keys and 12 and 14 rounds respectively. The core operations are identical; only the key schedule and round count differ.

Side-channel attacks.

A naive software AES that uses table lookups can leak bits of the key through cache timing — an attacker who can observe how long different encryptions take can, with enough samples, recover the key. Constant-time implementations and hardware AES instructions avoid this.

Modes of operation. 

Encrypting more than 16 bytes requires a mode of operation — CBC, CTR, GCM, CCM — to safely combine multiple AES invocations. AES on its own only handles 16 bytes; the modes are what make it useful on real messages.

Each of these topics is the subject of its own articles, but you now have the foundations to read them with comprehension.

08

A 30-second summary, for when you've finished reading

AES takes 16 bytes of plaintext and a 16-byte key, expands the key into eleven 16-byte round keys, arranges the plaintext in a 4×4 grid, and applies ten rounds of four operations: substitute bytes through a lookup table (SubBytes), shift the rows of the grid (ShiftRows), mix the bytes in each column with a special arithmetic (MixColumns), and XOR in a round key (AddRoundKey). The four operations together produce strong confusion and diffusion; ten rounds is enough that no known attack does meaningfully better than trying every possible key, which takes longer than the universe is old. Decryption runs the same operations in reverse with the round keys in reverse order. Every step is invertible by design. The whole thing fits in a few hundred lines of C code and runs in microseconds on any modern processor.

That is AES.

A companion to the LoRa encryption retrospective — written for anyone who wants to know exactly what is happening inside the AES block they read about somewhere.

Subhajit Roy

Subhajit Roy

Co-Founder & Embedded Engineer

Krishworks Technology Innovations

SHARE AT
grok-1
chatgpt-6
gemini-icon-logo
perplexity-color-1-

Explore more Articles

Scroll to Top
  • Schematic design
  • PCB and schematic source files
  • Assembling drawing files
  • Providing prototype/sample and production PCB service
  • Testing and validation of designed hardware
  • HIPAA
  • Azure Key
  • Management
  • ES, Checksum,
  • MD5sum
  • AWS
  • Azure
  • GCP
  • DigitalOcean
  • Kotlin
  • Python
  • Tensorflow
  • Computer Vision
  • ECG
  • SPO2
  • Heart Rate
  • Glucometer
  • Blood Pressure
  • UX UI Process
  • Figma and FigJam
  • Adobe Suite
  • Selenium Java
  • Postman
  • Swagger
  • Jmeter
  • SQL
  • Java Scripter
  • Test ng
  • Extents Reports
  • Flutter
  • Java
  • Kotlin
  • Swift
  • Dart
  • React JS
  • Python
  • NodeJS
  • Django
  • HTML, CSS, JS
RDBMS
  • PostgreSQL
  • Oracle
  • MySQL
  • MariaDB
No SQL Based
  • MongoDB
  • GCP
  • FirestoreDB
  • DynamoDB
  • Azure
  • CosmosDB
  • AWS