pk.org: Computer Security/Lecture Notes

Modern Symmetric Cryptography

Part 5 – Block ciphers, modes of operation, and stream ciphers

Paul Krzyzanowski – 2025-09-15

Part 1: Foundations of Cryptography
Part 2: Classical Ciphers
Part 3: Mechanized Cryptography
Part 4: Theoretical Breakthroughs
Part 5: Modern Symmetric Cryptography
Part 6: Principles of Good Cryptosystems
Part 7: Introduction to Cryptanalysis


Overview

Shannon's theoretical framework showed what secure ciphers needed to achieve: destroy the patterns in language through confusion and diffusion, repeated in multiple rounds. The mechanized era demonstrated that machines could apply complex transformations consistently and continuously. Modern symmetric cryptography combines these insights to create practical systems that implement Shannon's principles at the scale and speed that digital communications require.

This section covers the tools you'll actually encounter in protocols and libraries. We examine how modern block ciphers implement confusion and diffusion, look at specific systems like AES and ChaCha20, and address the practical question of how to use these primitives safely on real data that's longer than a single block.


Block ciphers in practice

A block cipher is a keyed permutation on \(n\)-bit strings. Given a secret key, it produces one permutation of the \(2^n\) possible blocks; change the key and you get another.

Modern block ciphers don't create complex permutations in one step. Instead, they use a round-based structure: apply a simple transformation repeatedly, mixing in key material each time.

The state is a small array of bytes that holds the intermediate values. Each round reads the current state, applies the round transformation, and produces the next state. A key schedule expands the master key into separate round keys so each round can mix in fresh key material.

After enough rounds, simple relationships between input, key, and output bits are destroyed. The avalanche effect ensures that changing one input bit affects many output bits in unpredictable ways.

Two architectural patterns

Two structural patterns dominate block cipher design: substitution–permutation networks and Feistel networks.

Substitution–permutation networks (SPNs)

A modern block cipher like AES is a substitution–permutation network (SPN).

We treat the input block as a state: a small array of bytes holding the work in progress.

Encryption runs in rounds. Each round repeats the same set of operations on the state: substitute, mix, and add key information:

  1. Substitution (confusion): Replace each byte using a fixed lookup table (an S-box). Each table maps a byte to another byte via a nonlinear rule, so simple XOR-based relationships do not survive.

  2. Permutation (diffusion): Rearrange the bytes to spread local changes.

  3. Key addition: Each round uses a round key. The key schedule expands the master key into a sequence of per-round keys. We combine the round key with the state by taking an exclusive-or of the current result to produce the state for the next round, written \(\text{state} \leftarrow \text{state} \oplus K_i\).

After enough rounds, small differences in the input or in the key affect many bytes of the state. That is Shannon’s confusion and diffusion in practice.

Decryption applies the inverse substitution and the inverse mixing, using the round keys in reverse order.

Feistel networks

Feistel networks solve a different problem: how do we build an invertible cipher even if the round computation itself is not invertible? This means that we don't need to design a function that performs an inverse operation for decrypting data.

As with SPNs, encryption uses multiple rounds, and each round gets a different round key derived from the master key. It applies the following steps:

  1. Split the block into two halves, left and right. In each round, compute a keyed function \(F\) on the right half: \(F(R_i, K_i)\).
  2. XOR the result into the left half, then swap halves: \[L_{i+1} = R_i,\qquad R_{i+1} = L_i \oplus F(R_i, K_i).\]

Repeat for several rounds. Here, \(F\) is any fast round function that takes the right half and a round key as parameters. It does not need to be invertible.

It is easy to see why this always reverses. After a round, the new left half is the old right half. During decryption, you already have it, so you recompute the same \(F\), undo the XOR, and swap back.

You never need to invert the round function. Decryption runs the same code with the round keys in reverse order.

DES is the classic Feistel cipher. It applies this structure for 16 rounds. Each round expands the right half, combines it with a round key, substitutes through small tables, permutes the result, XORs it into the left half, and swaps.


DES: commercial origins, structure, and modern limits

In the early 1970s, banks and companies needed a practical way to protect data as ATMs, electronic funds transfer, and shared computing grew. IBM built a family of ciphers under Horst Feistel for this market.

One of those designs, refined with feedback from the U.S. National Bureau of Standards (now NIST), became the Data Encryption Standard (DES) in 1977. The aim was a published, efficient standard that industry could implement.

Although it's most often implemented in software, DES was designed with hardware implementations in mind: the bit permutations and S-box lookups fit the chips of the day. The speed of computers of that time would otherwise use a significant chunk of computing time simply encrypting or decrypting data.

DES is a Feistel cipher that has the following structure:

Each round's \(F\) function:

  1. Expands 32 bits to 48 bits by duplication
  2. XORs with 48-bit round key
  3. Substitutes through eight 6→4 S-boxes
  4. Permutes the 32-bit result

The S-boxes were carefully engineered to resist differential cryptanalysis, which was not public knowledge until the 1990s, showing that DES designers understood attacks that wouldn't be published for another decade.

It is fair to say that DES is not fundamentally weak except for its key length. The 16-round structure and S-boxes still stand up well against known cryptanalysis. The problem is that a 56-bit key can be brute-forced; that was demonstrated in the late 1990s with purpose-built hardware. Brute-forcing simply means iterating through every possible key until you achieve a successful decryption. By the late 1990s, specialized hardware could break DES keys in days or hours.

The 64-bit block also runs into the birthday bound: collisions appear after about \(2^{n/2}\) samples. With \(n=64\), repeats are likely after roughly \(2^{32}\) blocks under one key (on the order of a few-hundred gigabytes), which weakens several modes.

Triple DES (3DES)**

To extend DES’s life, industry created triple-DES: using the DES algorithm in an encrypt–decrypt–encrypt (EDE) sequence:

3DES provided adequate key length but inherited the 64-bit block limitation and was slow on general-purpose processors. It served as a bridge until AES became available. Treat DES and 3DES as legacy.

AES: what Rijndael is and why it replaced DES

In 1997, NIST ran an open, international competition to replace DES. The winner, standardized as the Advanced Encryption Standard (AES) in 2001, is a cipher named Rijndael after its designers, Joan Daemen and Vincent Rijmen. “Rijndael” is part of a broader family of ciphers. It supports several block and key sizes. AES is the specific profile with a 128-bit block and key sizes of 128, 192, or 256 bits.

AES has this structure:

It represents the 128-bit state as a \(4\times 4\) array of bytes and applies a fixed round structure. Each round contains the following sequence of operations:

  1. SubBytes: Replace each byte using fixed 8×8 S-box. This is a lookup table with 256 entries. You give it one byte (0–255); it returns a different byte. The table is chosen so the mapping is nonlinear (no simple XOR rules apply). There is also an inverse table used during decryption.
  2. ShiftRows: Rotate each row by a different offset. This moves bytes to new columns. Row 0 is not rotated; row 1 is rotated by one position; row 2 by two positions; and row 3 by three positions.
  3. MixColumns: Linearly mix the four bytes in each column. This spreads local changes.
  4. AddRoundKey: XOR the round key into the state.

The final round omits MixColumns (a technicality needed for clean decryption).

A key schedule expands the master key into round keys and avoids simple relations that would leak structure. AES-128, AES-192, and AES-256 use 10, 12, and 14 rounds.

Why AES Succeeded

AES was chosen as a standard after much analysis:

If you need a block cipher, choose AES unless you have a specific, defensible reason not to.


Modes of operation: using block ciphers on real data

Block ciphers operate on one fixed-size block at a time. Files, packets, and records tend to be longer and typically span many such blocks.

A mode of operation defines how to apply a block cipher to whole messages. We will cover message authentication later, so we keep integrity details light here.

We will cover integrity later, but you will see one term now. AEAD (Authenticated Encryption with Associated Data) means “encrypt and also output a short tag to detect tampering.” Read AEAD as “encryption with a built-in tamper check.” We will return to the details when we discuss authentication.

Electronic Codebook (ECB)
ECB encrypts each block independently, applying the same mapping to every block under the same key. That makes it deterministic at the block level.
The consequence is leakage. Identical plaintext blocks produce identical ciphertext blocks. Repeated fields, aligned structures, and low-variation regions show up as repeated ciphertext blocks. Encrypting an image with ECB preserves visible outlines; encrypting a database column reveals which records share the same value.
ECB also enables simple cut-and-paste manipulations: an attacker can rearrange ciphertext blocks and produce a rearranged plaintext after decryption because each block is handled in isolation.
ECB is fine for test vectors and toy examples. Do not use it for data; prefer a mode that hides patterns (CBC, CTR) or, better, an AEAD (AES-GCM or ChaCha20-Poly1305).
Cipher Block Chaining (CBC)
CBC hides repeats by XORing each plaintext block with the previous ciphertext block before encryption. For the first block, use an initialization vector (IV): a per-message, random, unpredictable block XORed with the first plaintext so the same data under the same key encrypts differently each time. The initialization vector is not secret -- it is typically sent immediately before the ciphertext. It ensures that even identical plaintexts encrypted with the same key produce different ciphertext.
Counter mode (CTR)
CTR turns a block cipher into a keystream generator. Encrypt a sequence of per-message inputs and counters to create a keystream, then XOR with the plaintext. There is no padding. Both directions are parallelizable. Random access is easy. The per-message input must be unique for a given key. If you reuse it with the same key, you reuse the keystream, and XORing two ciphertexts reveals \(P_1\oplus P_2\).
Galois/Counter Mode (GCM)
GCM builds on CTR and also produces an authentication tag. For now, know that it gives you encryption plus a tag to detect tampering. GCM prefers a 96-bit per-message value (called a nonce) and requires uniqueness for a given key.

“If the message length isn’t a multiple of the block size, ECB and CBC require padding (e.g., defined by a PKCS#7 standard).. CTR, GCM, CFB/OFB, and stream ciphers like ChaCha20 don’t need padding because they encrypt a keystream and XOR it with the plaintext.”

To keep terminology manageable, we will skip storage-specific modes here, but note that more modes have been designed.

Practical rule. Choose an AEAD in real-world systems. If you have AES hardware, AES-GCM is usually the right choice. If you do not, use ChaCha20-Poly1305 in the next section.


Stream ciphers and ChaCha20

While block ciphers work on fixed-size chunks, stream ciphers generate a continuous keystream that's XORed with the plaintext. They're conceptually similar to the one-time pad, but with the pad (keystream) generated algorithmically from a key and per-message value using a CSPRNG (cryptographically-secure pseudorandom number generator).

Advantages of a stream cipher

Stream ciphers have a few attractive features:

Critical requirements

Stream ciphers simulate a one-time pad and have the same operational issue. You can never reuse keystreams, meaning that you cannot use the same key for two different messages since that will reveal the relationship between plaintexts: \(C_1 \oplus C_2 = P_1 \oplus P_2\).

This restriction would render stream ciphers useless, as you would need to generate a new key for each piece of data to be encrypted.

Different designs call it a nonce ("number used once") or an initialization vector (IV), and it is an extra parameter that is passed to the keystream generator along with the secret key. This ensures that the keystream will be different even with the same key since the nonce is randomly generated for each message. As with block modes, the nonce or initialization vector is not secret.

ChaCha20: A modern stream cipher

RC4 was once a common stream cipher on the web. Statistical biases and practical attacks ended its run.

ChaCha20 is the modern choice on general CPUs and on embedded systems.

ChaCha20's keystream generator is built from simple operations on 32-bit words: adds, rotates, and XORs.

These operations are fast on general-purpose processors and easy to implement in constant time, making ChaCha20 resistant to timing attacks.

The structure of ChaCha20 is:

ChaCha20 initializes a 512-bit state with key, nonce, counter, and constants, then applies 20 rounds to produce 512 bits of keystream. For longer messages, the counter increments to produce additional keystream blocks. That makes ChaCha20 a high-quality pseudorandom generator keyed by the secret and the nonce.

You then compute \[C = P \oplus \text{keystream}\] To decrypt, you compute \[P = C \oplus \text{keystream}\]

ChaCha20-Poly1305 AEAD

ChaCha20 almost always appears combined with Poly1305 authentication to create an AEAD (Authenticated Encryption with Associated Data) system called ChaCha20-Poly1305, which provides both confidentiality and integrity in one operation.

ChaCha20 is popular because it is fast without lookup tables, easy to implement in constant time, and resilient against cache-timing pitfalls. On some phones, small cores, and many embedded systems, it outperforms AES software. As with CTR and GCM, the nonce must be unique when using the same key.

When you have AES hardware, AES-GCM is usually the fastest safe choice. When you do not, ChaCha20-Poly1305 is typically faster and simpler to implement correctly. Both are solid when used correctly.


Reference: common ciphers and sizes

Core set you will actually choose:

Name Type Block/stream Typical key sizes Notes
AES-128/192/256 SPN block cipher 128-bit block 128/192/256-bit Default choice; broad hardware support
ChaCha20-Poly1305 Stream + authenticator (AEAD) Stream 256-bit (cipher) Fast without AES-NI; strong side-channel profile
DES Feistel block cipher 64-bit block 56-bit (effective) Legacy; brute-forceable; small block
3DES (EDE2/EDE3) Feistel block cipher 64-bit block 56, 112, or 168-bit (nominal) Legacy; slow

Optional ciphers you may see in standards/libraries:

Name Type Block/stream Typical key sizes Notes
Camellia Feistel-style block cipher 128-bit block 128/192/256-bit ISO standard; common in OpenSSL
SM4 Feistel-style block cipher 128-bit block 128-bit Chinese national standard; 32 rounds
ARIA SPN block cipher 128-bit block 128/192/256-bit Korean standard
SEED Feistel block cipher 128-bit block 128-bit Korean standard; legacy in some stacks
IDEA (legacy) Mixed-arithmetic block cipher 64-bit block 128-bit Early PGP; legacy only
GOST 28147-89 (legacy) Feistel cipher 64-bit block 256-bit Former Russian standard; lagacy

Takeaways

Pick AES for block-cipher deployments and ChaCha20-Poly1305 when AES hardware is weak.

Use an AEAD by default to ensure both confidentiality and integrity. We will cover authentication details later.

Treat the per-message input as a first-class parameter. In CBC, this is an IV (initialization vector): a fresh, unpredictable block used with the first plaintext block. In CTR, GCM, and ChaCha20, it is a per-message value (often called a nonce) that must be unique under a key. We will revisit “nonce” terminology when we cover authentication protocols.

Respect any per-key data limits that a standard calls out. Use constant-time implementations or hardware instructions to avoid timing leaks.

Most real failures are the same two mistakes: the wrong mode for the job, or reuse of a nonce/IV. Avoid those, and these ciphers will serve you well.


Next: Part 6: Principles of Good Cryptosystems