L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse

CS 161, Lesson 21, in 56 slides. It explains why CBC needs PKCS#7 padding while CTR does not, works the parallelization trade-offs between CBC and CTR, and shows why reusing an IV is catastrophic for CTR but merely contained for CBC. This is where IND-CPA is won or lost in practice. It is anchored to textbook sections 6.7 to 6.9.

Subject: Computer Security · 84 slides · applied lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. When the Last Block Doesn't Fit

Title

CS 161 · Lesson 21 of 45

PKCS#7 padding · the CBC-vs-CTR trade-off · why IV reuse can be catastrophic

2. By the end of this lesson you can…

Objectives

  1. Explain why CBC needs padding: a block cipher takes a fixed 128-bit input, and ⊕ with a 128-bit ciphertext block is undefined for a short last block.
  2. Apply PKCS#7 correctly — pad with N bytes each equal to N — including the edge case where a block-aligned message gets a whole extra block of padding.
  3. Explain why CTR mode needs no padding at all, and truncate the keystream for a short final block.
  4. Rank the severity of IV reuse: catastrophic for CTR (a two-time pad leaking M⊕M′) versus contained for CBC (only a shared-prefix leak).
  5. Read the master CBC-vs-CTR table — padding, parallelization, IV-reuse severity, E_K vs D_K — to choose a mode.

3. What survived from L20 · Block Ciphers, PRPs & Modes of Operation (ECB/CBC/CTR)?

Warm-up

Discussion prompt

Before we open L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse: without looking back, what was the main idea of L20 · Block Ciphers, PRPs & Modes of Operation (ECB/CBC/CTR), and what could you do by the end of it that you could not do before?

Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.

Answer:

CS 161, Lesson 20, in 52 slides. It explains what a block cipher is - a keyed permutation - why AES on its own is not IND-CPA even though it is a strong PRP, and how the modes of operation ECB, CBC, and CTR, together with parallelization, turn the primitive into a usable scheme. It is anchored to textbook sections 6.4 to 6.7.

4. Three loose ends from the modes lecture

Concept

L20 built CBC and CTR and proved they can be IND-CPA. This lesson closes the three engineering gaps that decide whether they actually are, in practice.

What if it doesn't fit?
§6.8 padding: CBC needs PKCS#7, CTR needs none
Which mode is faster?
§6.7 the parallelization trade-off
What if the IV repeats?
§6.9 catastrophic for CTR, contained for CBC

5. Which is which: Three loose ends from the modes lecture

Matching

Match the pairs

From Three loose ends from the modes lecture — match each one to what it actually does. The descriptions have been shuffled.

  • c1. What if it doesn't fit?
  • c2. Which mode is faster?
  • c3. What if the IV repeats?
  • b1. §6.8 padding: CBC needs PKCS#7, CTR needs none
  • b2. §6.7 the parallelization trade-off
  • b3. §6.9 catastrophic for CTR, contained for CBC

Why: What if it doesn't fit?, Which mode is faster?, What if the IV repeats? are easy to tell apart while they are sitting next to their descriptions and much harder afterwards, which is what this checks.

6. One fact to carry through the whole lesson

Concept

Throughout, the block size is 128 bits = 16 bytes — the AES block size. Every padding count, table, and edge case below is measured against that one number.

\[ \text{block size} = 128\ \text{bits} = 16\ \text{bytes} \]

7. Why CBC Needs Padding

Section

Part 1 · §6.8 the short-block problem

8. §6.8 A block cipher only eats whole blocks

Concept

A block cipher is a fixed-width gadget: it takes exactly 128 bits in and gives exactly 128 bits out. It has no notion of a 'partial' input.

CBC chains by feeding each plaintext block, ⊕'d with the previous ciphertext block, into that 128-bit gadget. So every plaintext block must be a full 128 bits.

9. Break it if you can: §6.8 A block cipher only eats whole blocks

Counterexample

Discussion prompt

A block cipher is a fixed-width gadget: it takes exactly 128 bits in and gives exactly 128 bits out. It has no notion of a 'partial' input.

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

Answer:

CBC chains by feeding each plaintext block, ⊕'d with the previous ciphertext block, into that 128-bit gadget. So every plaintext block must be a full 128 bits.

10. §6.8 The problem: a short last block

Concept

If the plaintext length isn't a multiple of 128 bits, the last CBC block comes up short. Say the final block is only 100 bits long.

\[ C_i = \mathrm{Enc}(K,\; M_i \oplus C_{i-1}) \]

To form that block, CBC wants to compute M_last ⊕ C_prev. But M_last is 100 bits and C_prev is 128 bits — and ⊕ needs two equal-length operands.

11. By analogy: §6.8 The problem: a short last block

Analogy

Discussion prompt

Explain §6.8 The problem: a short last block by analogy to something with no Computer Security in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

If the plaintext length isn't a multiple of 128 bits, the last CBC block comes up short. Say the final block is only 100 bits long.

12. §6.8 Why the short block is genuinely stuck

Intuition

⊕ is bitwise: it pairs up bit 1 with bit 1, bit 2 with bit 2, and so on. With 100 bits on one side and 128 on the other, 28 bits have no partner. There's simply nothing to XOR them against.

Even if you forced the 100-bit result through somehow, the block cipher wouldn't accept it — its input port is exactly 128 bits wide. The short block can't be fed in.

Ask yourself: what's the cheapest way to make a 100-bit block into a 128-bit block? (Add 28 more bits — that's all padding is.)

13. Teach it back: §6.8 Why the short block is genuinely stuck

Explain it

Discussion prompt

Explain §6.8 Why the short block is genuinely stuck to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

Even if you forced the 100-bit result through somehow, the block cipher wouldn't accept it — its input port is exactly 128 bits wide. The short block can't be fed in.

14. What has to happen first: §6.8 Trace the failure on a 100-bit tail

Ranking

Put in order

Put the moves of §6.8 Trace the failure on a 100-bit tail into the order they have to happen.

  1. Take a message whose last block has only 100 bits, with C_prev a full 128-bit ciphertext block
  2. Attempt M_last ⊕ C_prev
  3. Attempt to feed the result into Enc(K, ·) anyway
  4. Conclude: pad M_last up to 128 bits BEFORE the ⊕

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. This is the generic 'length not a multiple of 128' case — most real messages land here.

15. §6.8 Trace the failure on a 100-bit tail

Worked example

Take a message whose last block has only 100 bits, with C_prev a full 128-bit ciphertext block

Why: This is the generic 'length not a multiple of 128' case — most real messages land here.

Attempt M_last ⊕ C_prev

Why: ⊕ is defined only on equal-length operands; 100 vs 128 leaves 28 bits unpaired, so the operation is undefined.

Attempt to feed the result into Enc(K, ·) anyway

Why: The block cipher's input is fixed at 128 bits, so even a well-formed 100-bit string can't enter it.

Conclude: pad M_last up to 128 bits BEFORE the ⊕

Why: Padding to a multiple of the block size is the only fix that makes both the ⊕ and the block cipher well-defined — so CBC must pad.

16. Draw the shape of it: §6.8 Trace the failure on a 100-bit tail

Blank canvas

Draw it

Draw what §6.8 Trace the failure on a 100-bit tail just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

17. Something is wrong here: 'just XOR the first 100 bits and ignore 28'

Anomaly

Predict first

A student writes this, and it looks reasonable:

A student: 'The last block is 100 bits — just XOR it with the first 100 bits of C_prev and drop the other 28. No padding needed.'

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Now you have a 100-bit value, but the block cipher Enc(K, ·) still demands a 128-bit input — that input is undefined for the block cipher, so CBC can't continue.

A student: how do we make the last CBC block valid?

Why: Now you have a 100-bit value, but the block cipher Enc(K, ·) still demands a 128-bit input — that input is undefined for the block cipher, so CBC can't continue.

18. Trap: 'just XOR the first 100 bits and ignore 28'

Trap

The trap

A student: 'The last block is 100 bits — just XOR it with the first 100 bits of C_prev and drop the other 28. No padding needed.'

Truncate C_prev to 100 bits and XOR

Why: Now you have a 100-bit value, but the block cipher Enc(K, ·) still demands a 128-bit input — that input is undefined for the block cipher, so CBC can't continue.

The fix

A student: how do we make the last CBC block valid?

Pad M_last out to a full 128 bits, THEN XOR with the 128-bit C_prev and encrypt

Why: §6.8: only a full-width block can pass through both ⊕ and the block cipher. Truncating is undefined; padding is the defined fix.

19. PKCS#7: Unambiguous Padding

Section

Part 2 · §6.8 the right scheme

20. §6.8 Padding must be reversible

Concept

Padding only works if the receiver can strip exactly the bytes you added — no more, no less. So the rule isn't just 'fill to a multiple of 128'; it must be unambiguous on the way back.

The depadder sees only the decrypted bytes. From those bytes alone it has to know where the real message ends.

21. Plan first: §6.8 Depad must undo padding exactly

Step zero

Discussion prompt

§6.8 Depad must undo padding exactly — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: The sender pads, encrypts, and transmits; the receiver decrypts and…

Answer:

  1. The sender pads, encrypts, and transmits; the receiver decrypts and gets padded plaintext
  2. If the receiver strips too few bytes, junk pad bytes stay in M
  3. If the receiver strips too many bytes, real message bytes are lost
  4. Verify: the scheme must let the receiver compute the EXACT pad length from the bytes alone

22. §6.8 Depad must undo padding exactly

Worked example

The sender pads, encrypts, and transmits; the receiver decrypts and gets padded plaintext

Why: Decryption recovers M plus whatever bytes were appended — the receiver must now find and remove exactly those bytes.

If the receiver strips too few bytes, junk pad bytes stay in M

Why: The message is corrupted with trailing garbage that was never part of it.

If the receiver strips too many bytes, real message bytes are lost

Why: Now genuine data is gone. Either error means the padding scheme failed its one job.

Verify: the scheme must let the receiver compute the EXACT pad length from the bytes alone

Why: §6.8: padding is correct only if depadding is unambiguous — this is precisely what PKCS#7 guarantees and 'all 1s' does not.

23. §6.8 A bad scheme: pad with all 1s

Intuition

Tempting idea: fill the tail with 1 bits. Quick, simple. But now decrypt and look at the last byte: 0000000010111111. How many of those trailing 1s were padding?

You can't tell. Maybe the message ended in real 1 bits; maybe they were all padding. The scheme is ambiguous, so depadding is impossible. We need padding that encodes its own length.

Ask yourself: what's the smallest thing you could write into the pad so the receiver always knows how much to remove? (The count itself.)

24. §6.8 PKCS#7, stated

Concept

PKCS#7 padding — To pad a message, compute N = the number of padding bytes needed to reach a multiple of the block size, then append N bytes, each holding the value N. To depad, read the last byte to get N and strip that many bytes.

The padding literally writes down its own length, repeated. The final byte always tells the receiver exactly how many bytes to remove.

25. Plan first: §6.8 Pad and depad a 3-short message

Step zero

Discussion prompt

§6.8 Pad and depad a 3-short message — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: Suppose the message is 3 bytes short of a 16-byte block, so N = 3

Answer:

  1. Suppose the message is 3 bytes short of a 16-byte block, so N = 3
  2. Append three bytes, each equal to 0x03: … 03 03 03
  3. To depad: decrypt, read the last byte (0x03), strip 3 bytes

26. §6.8 Pad and depad a 3-short message

Worked example

Suppose the message is 3 bytes short of a 16-byte block, so N = 3

Why: N is whatever it takes to reach the next multiple of the block size — here, 3 bytes.

Append three bytes, each equal to 0x03: … 03 03 03

Why: PKCS#7 rule: append N bytes each of value N. The pad encodes its own length three times over.

\[ M \;\Vert\; \texttt{03}\ \texttt{03}\ \texttt{03} \]

To depad: decrypt, read the last byte (0x03), strip 3 bytes

Why: The last byte names N unambiguously, so the receiver removes exactly the 3 bytes that were added — recovering M exactly.

27. Decode the notation: §6.8 Pad and depad a 3-short message

Notation

Annotate

From §6.8 Pad and depad a 3-short message — read this one piece at a time. What is each part doing?

On: \( M \;\Vert\; \texttt{03}\ \texttt{03}\ \texttt{03} \)

  • N is whatever it takes to reach the next multiple of the block size — here, 3 bytes.
  • PKCS#7 rule: append N bytes each of value N. The pad encodes its own length three times over.
  • The last byte names N unambiguously, so the receiver removes exactly the 3 bytes that were added — recovering M exactly.

28. §6.8 The crucial edge case: already aligned

Concept

What if the plaintext is already an exact multiple of the block size? Then N = 0 padding bytes 'needed' — but appending nothing breaks the rule that the last byte always names the pad length.

PKCS#7's fix: append a whole new block of padding — 16 bytes, each 0x10 (decimal 16). There is now always exactly one unambiguous padding pattern, even for aligned messages.

29. What has to happen first: §6.8 Why the aligned case must add a full block

Ranking

Put in order

Put the moves of §6.8 Why the aligned case must add a full block into the order they have to happen.

  1. Suppose M is exactly 32 bytes — two full blocks — and we add NO padding
  2. Now imagine a DIFFERENT message that genuinely ended in the byte 0x10 by coincidence
  3. Fix: when aligned, append a full 16-byte block of 0x10
  4. Verify: depad reads 0x10 = 16, strips exactly 16 bytes, recovers the original 32-byte M

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. It already fits the block cipher, so adding nothing seems harmless.

30. §6.8 Why the aligned case must add a full block

Worked example

Suppose M is exactly 32 bytes — two full blocks — and we add NO padding

Why: It already fits the block cipher, so adding nothing seems harmless.

Now imagine a DIFFERENT message that genuinely ended in the byte 0x10 by coincidence

Why: The depadder, seeing a final 0x10, would strip 16 real message bytes — corrupting a legitimate message.

Fix: when aligned, append a full 16-byte block of 0x10

Why: Now the receiver ALWAYS reads the last byte as a pad count and ALWAYS strips that many — there is never a case with no padding to interpret.

Verify: depad reads 0x10 = 16, strips exactly 16 bytes, recovers the original 32-byte M

Why: §6.8: a single, always-present padding pattern is what keeps depadding unambiguous in every case.

31. §6.8 Why the pad repeats the count

Intuition

PKCS#7 could in principle write the count once. Repeating it N times is what makes depadding robust and self-describing: the very last byte — wherever it lands — names the length, every time.

And the values 1 through 16 fit in a single byte, which is exactly the range of possible pad lengths for a 16-byte block. The count and the byte width line up perfectly.

Ask yourself: for a 16-byte block, what's the largest pad length you'd ever write — and does it fit in one byte? (16 = 0x10, yes.)

32. §6.8 The PKCS#7 reference table

Concept

One table covers every case. Read it as: how short the message is → what you append → how the receiver reads it back.

Padding bytes needed (N)Bytes appendedHow depad reads it
303 03 03Last byte = 3 → strip 3 bytes
101Last byte = 1 → strip 1 byte
707 07 07 07 07 07 07Last byte = 7 → strip 7 bytes
0 (already aligned)a full block: 10 × (0x10)Last byte = 16 → strip 16 bytes

Note the bottom row: 'needs 0' still appends a whole 16-byte block. That is the non-negotiable part of PKCS#7.

33. Fill in: Bytes appended for §6.8 The PKCS#7 reference table

Comparison

Comparison matrix

From §6.8 The PKCS#7 reference table: refill the Bytes appended column from what you know. The rest of the table is as it appeared.

Padding bytes needed (N)Bytes appendedHow depad reads it
303 03 03Last byte = 3 → strip 3 bytes
101Last byte = 1 → strip 1 byte
707 07 07 07 07 07 07Last byte = 7 → strip 7 bytes
0 (already aligned)a full block: 10 × (0x10)Last byte = 16 → strip 16 bytes

34. Something is wrong here: 'an aligned message needs no padding'

Anomaly

Predict first

A student writes this, and it looks reasonable:

A student: 'My plaintext is exactly 48 bytes — three whole blocks. It fits the cipher perfectly, so PKCS#7 adds nothing.'

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Now depadding is ambiguous: if the real last byte happens to be a small value, the receiver can't tell message bytes from pad bytes.

A student: what does PKCS#7 do to a block-aligned message?

Why: Now depadding is ambiguous: if the real last byte happens to be a small value, the receiver can't tell message bytes from pad bytes. The scheme breaks.

35. Trap: 'an aligned message needs no padding'

Trap

The trap

A student: 'My plaintext is exactly 48 bytes — three whole blocks. It fits the cipher perfectly, so PKCS#7 adds nothing.'

Append zero padding to the aligned message

Why: Now depadding is ambiguous: if the real last byte happens to be a small value, the receiver can't tell message bytes from pad bytes. The scheme breaks.

The fix

A student: what does PKCS#7 do to a block-aligned message?

Append a FULL extra block of 16 bytes, each 0x10

Why: §6.8 / RFC 5652: PKCS#7 always adds 1–16 bytes, never 0. The aligned case gets a whole block so the last byte always names a valid pad length.

36. Why CTR Needs No Padding

Section

Part 3 · §6.8 stream-like modes

37. §6.8 CTR never feeds plaintext into the cipher

Concept

CTR runs the block cipher on a counter, not on the plaintext. It produces a keystream and ⊕s the plaintext with it — the plaintext is never an input to Enc.

\[ C_i = M_i \oplus \mathrm{Enc}(K,\; \text{IV} \Vert i) \]

Because the ciphertext is never fed back into the block cipher, a short final block creates no width mismatch at the cipher's input. CTR is essentially a stream cipher.

38. §6.8 CTR is a one-time pad you can trim

Intuition

Think of CTR as manufacturing a long pseudorandom pad — one block of keystream per counter value — and XORing the message onto it, exactly like a one-time pad.

If the message is shorter than the pad, you just throw away the extra pad bits. A 100-bit tail XORs against the first 100 keystream bits; the remaining 28 keystream bits are discarded. The last ciphertext block is simply 100 bits.

Ask yourself: with a one-time pad, does it matter that you generated more pad than message? (No — extra pad is harmless, you just don't use it.)

39. Plan first: §6.8 Encrypt and decrypt a 100-bit tail in CTR

Step zero

Discussion prompt

§6.8 Encrypt and decrypt a 100-bit tail in CTR — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: Generate the keystream block for the final counter: K_last = Enc(K…

Answer:

  1. Generate the keystream block for the final counter: K_last = Enc(K, IV ‖ i), a full 128 bits
  2. XOR the 100-bit plaintext tail with the FIRST 100 bits of K_last; discard the remaining 28
  3. Emit a 100-bit final ciphertext block — no padding added
  4. Verify decryption mirrors it: regenerate K_last, XOR the first 100 bits with the 100-bit ciphertext tail

40. §6.8 Encrypt and decrypt a 100-bit tail in CTR

Worked example

Generate the keystream block for the final counter: K_last = Enc(K, IV ‖ i), a full 128 bits

Why: CTR always produces full 128-bit keystream blocks — the cipher input is the counter, which is always full width.

XOR the 100-bit plaintext tail with the FIRST 100 bits of K_last; discard the remaining 28

Why: Only as much keystream as there is plaintext is used; the surplus pad bits are thrown away, OTP-style.

Emit a 100-bit final ciphertext block — no padding added

Why: The ciphertext tail is the same length as the plaintext tail, so the message length is preserved with zero overhead.

Verify decryption mirrors it: regenerate K_last, XOR the first 100 bits with the 100-bit ciphertext tail

Why: M ⊕ K ⊕ K = M. The receiver recreates the same keystream and truncates identically — recovering the exact 100-bit tail.

41. Where does each piece belong: L21 · Padding (PKCS#7), Parallelization…

Sorting

Sort into buckets

These are the pieces of L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse, out of order. Put each one back under the part of the lesson it belongs to.

Why CBC Needs Padding
§6.8 A block cipher only eats whole blocks; §6.8 The problem: a short last block; §6.8 Why the short block is genuinely stuck
PKCS#7: Unambiguous Padding
§6.8 Padding must be reversible; §6.8 Depad must undo padding exactly; §6.8 A bad scheme: pad with all 1s
Why CTR Needs No Padding
§6.8 CTR never feeds plaintext into the cipher; §6.8 CTR is a one-time pad you can trim; §6.8 Encrypt and decrypt a 100-bit tail in CTR
s1
Why CBC Needs Padding is where L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse puts §6.8 A block cipher only eats whole blocks, §6.8 The problem: a short last block, §6.8 Why the short block is genuinely stuck. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s2
PKCS#7: Unambiguous Padding is where L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse puts §6.8 Padding must be reversible, §6.8 Depad must undo padding exactly, §6.8 A bad scheme: pad with all 1s. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s3
Why CTR Needs No Padding is where L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse puts §6.8 CTR never feeds plaintext into the cipher, §6.8 CTR is a one-time pad you can trim, §6.8 Encrypt and decrypt a 100-bit tail in CTR. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.

42. §6.8 Side by side: CBC must pad, CTR truncates

Concept

The whole §6.8 story collapses into one contrast: feedback into the block cipher forces padding; a keystream you can trim does not.

Short last blockCBCCTR
Plaintext enters Enc?Yes (via ⊕ with C_prev)No — only the counter does
Width mismatch?Yes — undefined ⊕ / cipher inputNo — XOR only the bits you have
FixPad to a full block (PKCS#7)Truncate the keystream
Ciphertext lengthRounded up to a block multipleSame length as the plaintext

43. What each one costs: §6.8 Side by side: CBC must pad, CTR truncates

Trade off

Comparison matrix

From §6.8 Side by side: CBC must pad, CTR truncates: every row here is a choice with a cost. Fill the CBC column, then say which row you would actually pick and what you give up for it.

Short last blockCBCCTR
Plaintext enters Enc?Yes (via ⊕ with C_prev)No — only the counter does
Width mismatch?Yes — undefined ⊕ / cipher inputNo — XOR only the bits you have
FixPad to a full block (PKCS#7)Truncate the keystream
Ciphertext lengthRounded up to a block multipleSame length as the plaintext

44. Something is wrong here: 'all modes need padding'

Anomaly

Predict first

A student writes this, and it looks reasonable:

A student: 'Block ciphers work on 128-bit blocks, so EVERY mode has to pad short messages — CTR included.'

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Unnecessary, and it changes the ciphertext length for no reason.

A student: which modes actually need padding?

Why: Unnecessary, and it changes the ciphertext length for no reason. CTR feeds the counter — not the plaintext — into the cipher, so a short tail is never a problem.

45. Trap: 'all modes need padding'

Trap

The trap

A student: 'Block ciphers work on 128-bit blocks, so EVERY mode has to pad short messages — CTR included.'

Add PKCS#7 padding to a CTR message

Why: Unnecessary, and it changes the ciphertext length for no reason. CTR feeds the counter — not the plaintext — into the cipher, so a short tail is never a problem.

The fix

A student: which modes actually need padding?

Only block-feedback modes like CBC pad; stream-like modes like CTR truncate the keystream instead

Why: §6.8: padding is required when the plaintext is fed into the block cipher. CTR never does that, so it needs no padding at all.

46. The Danger of IV Reuse

Section

Part 4 · §6.9 fresh IVs are mandatory

47. §6.8 Why feedback is the dividing line

Intuition

The real question for any mode is simple: does the plaintext ever get fed INTO the block cipher? If yes, every input must be exactly 128 bits — so you must pad.

CBC feeds M ⊕ C_prev into Enc, so it pads. CTR feeds only the counter into Enc and XORs the plaintext outside the cipher, so it doesn't. One structural question decides padding for the whole mode.

Ask yourself: for a brand-new mode you've never seen, how would you predict whether it needs padding? (Check whether plaintext enters the block cipher.)

48. §6.9 Why we added an IV in the first place

Concept

ECB is deterministic — the same plaintext block always gives the same ciphertext block, which leaks (L20). Every secure mode adds a random IV so that encrypting the same plaintext twice gives different ciphertext.

So the rule is absolute: always use a fresh, random, unpredictable IV for every encryption. The IV is what makes the scheme randomized — and randomization is what buys IND-CPA.

49. §6.9 Reuse re-creates determinism

Concept

Reusing an IV throws away the one thing the IV was for. With a fixed IV, encrypting the same plaintext twice gives the same ciphertext again — the scheme is deterministic again.

And from L18 we know determinism breaks IND-CPA. So IV reuse is not a minor slip; it is a return to a leaking scheme. But HOW badly it leaks depends on the mode.

50. §6.9 CTR reuse is literally a two-time pad

Intuition

CTR's keystream depends only on the key and the IV/nonce. Reuse the IV, and you reuse the exact same keystream for a second message — the textbook two-time pad mistake from L19.

With a two-time pad, XOR the two ciphertexts and the keystream cancels, handing the attacker M ⊕ M′ — the bitwise XOR of the two plaintexts. That's catastrophic: known structure in one message peels the other open.

Ask yourself: in C = M ⊕ K and C′ = M′ ⊕ K with the SAME K, what is C ⊕ C′? (The K's cancel: M ⊕ M′.)

51. Plan first: §6.9 Compute the CTR two-time-pad leak

Step zero

Discussion prompt

§6.9 Compute the CTR two-time-pad leak — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.

Hint: It starts with: Encrypt M under nonce IV: C = M ⊕ K, where K = the CTR keystream from…

Answer:

  1. Encrypt M under nonce IV: C = M ⊕ K, where K = the CTR keystream from (key, IV)
  2. Reuse the SAME IV to encrypt M′: C′ = M′ ⊕ K
  3. The attacker, seeing C and C′, computes C ⊕ C′ and obtains M ⊕ M′
  4. Verify the damage: any guessed/known bytes of M reveal the same bytes of M′, and vice versa

52. §6.9 Compute the CTR two-time-pad leak

Worked example

Encrypt M under nonce IV: C = M ⊕ K, where K = the CTR keystream from (key, IV)

Why: CTR is a one-time pad whose pad K is fixed once the key and IV are fixed.

Reuse the SAME IV to encrypt M′: C′ = M′ ⊕ K

Why: Same key, same IV ⇒ identical keystream K. This is the forbidden reuse.

\[ C \oplus C' = (M \oplus K) \oplus (M' \oplus K) = M \oplus M' \]

The attacker, seeing C and C′, computes C ⊕ C′ and obtains M ⊕ M′

Why: The keystream cancels entirely. Eve never needs the key — she gets the XOR of the two plaintexts directly.

Verify the damage: any guessed/known bytes of M reveal the same bytes of M′, and vice versa

Why: §6.9: this is exactly the L19 two-time pad. CTR IV reuse is catastrophic — it leaks plaintext relationships outright.

53. Decode the notation: §6.9 Compute the CTR two-time-pad leak

Notation

Annotate

From §6.9 Compute the CTR two-time-pad leak — read this one piece at a time. What is each part doing?

On: \( C \oplus C' = (M \oplus K) \oplus (M' \oplus K) = M \oplus M' \)

  • CTR is a one-time pad whose pad K is fixed once the key and IV are fixed.
  • Same key, same IV ⇒ identical keystream K. This is the forbidden reuse.
  • The keystream cancels entirely. Eve never needs the key — she gets the XOR of the two plaintexts directly.

54. §6.9 CBC reuse is less severe

Concept

CBC also becomes deterministic under a reused IV, but the leak is contained. It only reveals whether two messages start with the same blocks — up to the first block where they differ.

Because each CBC block is chained through the unpredictable previous ciphertext, the moment the two plaintexts differ, their ciphertext streams diverge and stay divergent. Eve learns the shared prefix length, nothing more.

55. What has to happen first: §6.9 Trace the CBC shared-prefix leak

Ranking

Put in order

Put the moves of §6.9 Trace the CBC shared-prefix leak into the order they have to happen.

  1. Encrypt M = [P1, P2, P3] and M′ = [P1, P2, Q3] under the SAME IV
  2. Block 1: both compute Enc(K, P1 ⊕ IV) → the SAME C1
  3. Block 2: both compute Enc(K, P2 ⊕ C1) → the SAME C2
  4. Block 3: P3 ⊕ C2 ≠ Q3 ⊕ C2, so C3 ≠ C3′ — and everything after diverges
  5. Verify the contrast: CBC leaked a prefix, CTR leaked M ⊕ M′ entirely

Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. The two messages share their first two blocks and differ only in the third.

56. §6.9 Trace the CBC shared-prefix leak

Worked example

Encrypt M = [P1, P2, P3] and M′ = [P1, P2, Q3] under the SAME IV

Why: The two messages share their first two blocks and differ only in the third.

Block 1: both compute Enc(K, P1 ⊕ IV) → the SAME C1

Why: Same IV, same P1 ⇒ identical first ciphertext block. Eve sees C1 = C1′ and learns the first blocks match.

Block 2: both compute Enc(K, P2 ⊕ C1) → the SAME C2

Why: The chaining input is identical (same P2, same C1), so C2 = C2′. Eve learns the second blocks match too.

Block 3: P3 ⊕ C2 ≠ Q3 ⊕ C2, so C3 ≠ C3′ — and everything after diverges

Why: The first differing block breaks the chain; from here the ciphertexts share nothing. Eve learns only the shared-prefix length — not M ⊕ M′.

Verify the contrast: CBC leaked a prefix, CTR leaked M ⊕ M′ entirely

Why: §6.9: CBC reuse is contained (a structural prefix hint); CTR reuse is catastrophic (full plaintext-XOR). Same mistake, very different blast radius.

57. Draw the shape of it: §6.9 Trace the CBC shared-prefix leak

Blank canvas

Draw it

Draw what §6.9 Trace the CBC shared-prefix leak just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.

58. §6.9 Reading the M ⊕ M′ leak like an attacker

Intuition

Knowing M ⊕ M′ sounds abstract, but it's a crowbar. Wherever you can guess bytes of one message — a fixed header, a known greeting, a protocol field — you XOR them out and read the same bytes of the OTHER message for free.

With three or more messages under one reused nonce, natural-language redundancy alone is often enough to recover all of them. This is why CTR nonce reuse is treated as a total break.

Ask yourself: if you know M starts with 'GET /' and you hold M ⊕ M′, what do you immediately learn about M′? (Its first five bytes.)

59. Teach it back: §6.9 Reading the M ⊕ M′ leak like an attacker

Explain it

Discussion prompt

Explain §6.9 Reading the M ⊕ M′ leak like an attacker to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.

Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.

Answer:

With three or more messages under one reused nonce, natural-language redundancy alone is often enough to recover all of them. This is why CTR nonce reuse is treated as a total break.

60. §6.9 The severity table

Concept

ModeEffect of IV reuseWhat the attacker learns
CTRCatastrophic — two-time padM ⊕ M′ for the whole message (keystream cancels)
CBCContainedWhether two messages share leading blocks, up to the first difference

Same root cause (lost randomness, scheme goes deterministic), wildly different consequences. Never reuse an IV — but understand that CTR is the one where reuse is an instant disaster.

61. Fill in: Effect of IV reuse for §6.9 The severity table

Comparison

Comparison matrix

From §6.9 The severity table: refill the Effect of IV reuse column from what you know. The rest of the table is as it appeared.

ModeEffect of IV reuseWhat the attacker learns
CTRCatastrophic — two-time padM ⊕ M′ for the whole message (keystream cancels)
CBCContainedWhether two messages share leading blocks, up to the first difference

62. Something is wrong here: 'IV reuse leaks the same in CBC and CTR'

Anomaly

Predict first

A student writes this, and it looks reasonable:

A student: 'IV reuse is bad, sure, but it's equally bad in CBC and CTR — it's the same mistake either way.'

It is wrong. Say what breaks — and say it before you turn the page.

Correct: False. In CTR the keystream cancels and the attacker recovers M ⊕ M′ for the ENTIRE message — full plaintext relationships.

A student: how does IV-reuse severity differ by mode?

Why: False. In CTR the keystream cancels and the attacker recovers M ⊕ M′ for the ENTIRE message — full plaintext relationships. That's far worse than CBC's leak.

63. Trap: 'IV reuse leaks the same in CBC and CTR'

Trap

The trap

A student: 'IV reuse is bad, sure, but it's equally bad in CBC and CTR — it's the same mistake either way.'

Treat the two leaks as interchangeable

Why: False. In CTR the keystream cancels and the attacker recovers M ⊕ M′ for the ENTIRE message — full plaintext relationships. That's far worse than CBC's leak.

The fix

A student: how does IV-reuse severity differ by mode?

CTR reuse = two-time pad ⇒ M ⊕ M′ leaks (catastrophic). CBC reuse ⇒ only a shared-prefix hint (contained)

Why: §6.9: CTR's keystream depends only on (key, IV), so reuse repeats the whole pad. CBC's chaining limits the leak to the matching prefix.

64. Something is wrong here: 'a fixed, predictable IV is fine'

Anomaly

Predict first

A student writes this, and it looks reasonable:

A student: 'I'll just use a counter 0, 1, 2… as my IV, or even a constant — as long as it's there, the scheme is randomized.'

It is wrong. Say what breaks — and say it before you turn the page.

Correct: A constant IV is reuse (instant determinism).

A student: what must an IV actually be?

Why: A constant IV is reuse (instant determinism). A predictable IV lets the attacker influence what gets ⊕'d in — the chosen-IV/chosen-plaintext setting that breaks CBC's IND-CPA.

65. Trap: 'a fixed, predictable IV is fine'

Trap

The trap

A student: 'I'll just use a counter 0, 1, 2… as my IV, or even a constant — as long as it's there, the scheme is randomized.'

Use a predictable or constant IV

Why: A constant IV is reuse (instant determinism). A predictable IV lets the attacker influence what gets ⊕'d in — the chosen-IV/chosen-plaintext setting that breaks CBC's IND-CPA.

The fix

A student: what must an IV actually be?

Use a FRESH, RANDOM, UNPREDICTABLE IV for every single encryption

Why: §6.9 / NIST SP 800-38A: CBC needs an unpredictable IV and CTR needs unique counter blocks. 'Present' isn't enough — it must be fresh and unguessable.

66. Which of these survive contact with L21 · Padding (PKCS#7), Parallelization…?

Two truths and a lie

Sort into buckets

Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.

Holds up
L20 built CBC and CTR and proved they can be IND-CPA. This lesson closes the three engineering gaps that decide whether they actually are, in practice.; A block cipher is a fixed-width gadget: it takes exactly 128 bits in and gives exactly 128 bits out. It has no notion of a 'partial' input.; If the plaintext length isn't a multiple of 128 bits, the last CBC block comes up short. Say the final block is only 100 bits long.
Breaks
A student: 'The last block is 100 bits — just XOR it with the first 100 bits of C_prev and drop the other 28. No padding needed.'; A student: 'My plaintext is exactly 48 bytes — three whole blocks. It fits the cipher perfectly, so PKCS#7 adds nothing.'
sound
These are stated as this lesson states them — each one survives the edge cases L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

67. §6.9 Why CBC contains what CTR cannot

Intuition

In CTR the keystream is the WHOLE story: it depends only on key and IV, so repeating the IV repeats the entire pad — the messages cancel completely under XOR. There's no per-block structure to limit the damage.

In CBC each block is re-randomized by the previous CIPHERTEXT block. The instant two plaintexts differ, their ciphertext chains diverge and never realign — so the leak self-limits to the matching prefix.

Ask yourself: why doesn't the CBC leak spread past the first difference? (The differing block changes C, which changes every chaining input after it.)

68. By analogy: §6.9 Why CBC contains what CTR cannot

Analogy

Discussion prompt

Explain §6.9 Why CBC contains what CTR cannot by analogy to something with no Computer Security in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.

Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.

Answer:

Ask yourself: why doesn't the CBC leak spread past the first difference? (The differing block changes C, which changes every chaining input after it.)

69. Choosing a Mode: CBC vs CTR

Section

Part 5 · §6.7 the master trade-off

70. §6.7 Parallelization recap

Concept

From §6.7: CBC encryption is sequential — each block's ⊕ input is the previous ciphertext block, so you can't start block i until block i−1 is done. CTR has no such chain: every keystream block depends only on its counter.

So CTR encryption parallelizes; CBC encryption does not. Decryption is friendlier: CBC decryption parallelizes (each plaintext block needs only its own and the previous ciphertext block, both already known), and CTR decryption parallelizes too.

71. §6.7 The master CBC-vs-CTR table

Concept

Everything from this lesson, consolidated. This is the table you actually use when picking a mode.

PropertyCBCCTR
Padding required?Yes (PKCS#7)No (truncate keystream)
Encryption parallelizable?No (sequential chain)Yes (per-counter)
Decryption parallelizable?YesYes
IV-reuse severityContained (shared prefix)Catastrophic (M ⊕ M′)
Uses the decryption function D_K?Yes (to decrypt)No — only E_K, both ways

72. Fill in: CTR for §6.7 The master CBC-vs-CTR table

Comparison

Comparison matrix

From §6.7 The master CBC-vs-CTR table: refill the CTR column from what you know. The rest of the table is as it appeared.

PropertyCBCCTR
Padding required?Yes (PKCS#7)No (truncate keystream)
Encryption parallelizable?No (sequential chain)Yes (per-counter)
Decryption parallelizable?YesYes
IV-reuse severityContained (shared prefix)Catastrophic (M ⊕ M′)
Uses the decryption function D_K?Yes (to decrypt)No — only E_K, both ways

73. §6.7 What the table tells you to pick

Intuition

High-performance systems lean toward CTR: encryption parallelizes, there's no padding overhead, and you only ever need the forward block-cipher function E_K. The price is strict: you MUST guarantee nonce uniqueness, because reuse is catastrophic.

CBC tolerates an IV slip more gracefully (a contained leak), and needs no separate guarantee beyond an unpredictable IV — but it can't parallelize encryption and requires padding plus the decryption function.

Ask yourself: if you can't be certain your nonces are unique, which mode is the safer default? (CBC — its reuse failure is contained, not catastrophic.)

74. Break it if you can: §6.7 What the table tells you to pick

Counterexample

Discussion prompt

Ask yourself: if you can't be certain your nonces are unique, which mode is the safer default? (CBC — its reuse failure is contained, not catastrophic.)

That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.

Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.

75. Without one step: The padding & IV checklist

Constraint

Discussion prompt

Run The padding & IV checklist with this step confiscated:

Use a fresh, random, unpredictable IV every time. 'Present' is not enough — predictable or constant IVs break security.

Is it still possible? If it is, say what takes its place and what it costs you. If it is not, say exactly what that step was providing that nothing else does.

Hint: A step you can drop for free was never load-bearing. If you cannot drop it, name the thing that goes wrong the moment it is gone.

Answer:

  1. Block size is 128 bits = 16 bytes. Measure every pad count against it.
  2. CBC: pad with PKCS#7 — append N bytes each equal to N; if already aligned, append a FULL 16-byte block of 0x10. Depad by reading the last byte.
  3. CTR: never pad — XOR only as many keystream bits as you have plaintext, discard the rest; the ciphertext is the same length as the message.
  4. Use a fresh, random, unpredictable IV every time. 'Present' is not enough — predictable or constant IVs break security.
  5. Know the reuse blast radius: CTR reuse = two-time pad ⇒ M ⊕ M′ (catastrophic); CBC reuse ⇒ shared-prefix hint (contained).
  6. Pick the mode by trade-off: CTR for speed + parallel encryption (but guarantee nonce uniqueness); CBC when reuse must fail gracefully.

76. The padding & IV checklist

Pattern

  1. Block size is 128 bits = 16 bytes. Measure every pad count against it.
  2. CBC: pad with PKCS#7 — append N bytes each equal to N; if already aligned, append a FULL 16-byte block of 0x10. Depad by reading the last byte.
  3. CTR: never pad — XOR only as many keystream bits as you have plaintext, discard the rest; the ciphertext is the same length as the message.
  4. Use a fresh, random, unpredictable IV every time. 'Present' is not enough — predictable or constant IVs break security.
  5. Know the reuse blast radius: CTR reuse = two-time pad ⇒ M ⊕ M′ (catastrophic); CBC reuse ⇒ shared-prefix hint (contained).
  6. Pick the mode by trade-off: CTR for speed + parallel encryption (but guarantee nonce uniqueness); CBC when reuse must fail gracefully.

77. Where does it stop working: The padding & IV checklist

Edge cases

Discussion prompt

The padding & IV checklist works on the cases you have just seen. Push it to the edge: what is the most degenerate input it still handles — empty, zero, one item, everything equal — and what is the first case where it stops being true? Name the case, not just "it breaks".

Hint: Try the smallest legal input, then the largest, then the one where two things collide. Methods are specified at their edges; the middle takes care of itself.

Answer:

  1. Block size is 128 bits = 16 bytes. Measure every pad count against it.
  2. CBC: pad with PKCS#7 — append N bytes each equal to N; if already aligned, append a FULL 16-byte block of 0x10. Depad by reading the last byte.
  3. CTR: never pad — XOR only as many keystream bits as you have plaintext, discard the rest; the ciphertext is the same length as the message.
  4. Use a fresh, random, unpredictable IV every time. 'Present' is not enough — predictable or constant IVs break security.
  5. Know the reuse blast radius: CTR reuse = two-time pad ⇒ M ⊕ M′ (catastrophic); CBC reuse ⇒ shared-prefix hint (contained).
  6. Pick the mode by trade-off: CTR for speed + parallel encryption (but guarantee nonce uniqueness); CBC when reuse must fail gracefully.

78. Rule out three: Checkpoint — PKCS#7 on an aligned message

Elimination

Eliminate the wrong options

Using PKCS#7 with a 16-byte block size, how much padding does a 32-byte (block-aligned) message get?

3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.

  • A. 0 bytes — it already fills whole blocks, so no padding is needed.
  • B. 16 bytes — a full extra block, each byte equal to 0x10.
  • C. Pad to the next block with 1 bits until it's full, then stop.
  • D. 8 bytes, each equal to 0x08, to half-fill a new block.

Survives elimination: B

Why: §6.8 / RFC 5652: PKCS#7 always appends 1–16 bytes, never 0. When the message is already block-aligned, it appends a WHOLE new block — 16 bytes each holding the value 16 (0x10) — so the receiver always reads the last byte as the pad count and strips exactly that many. Depad here reads 0x10 = 16 and removes 16 bytes, recovering the original 32.

79. Checkpoint — PKCS#7 on an aligned message

Check

An engineer is CBC-encrypting a message that is exactly 32 bytes long — two full 16-byte blocks. They ask how many bytes of PKCS#7 padding to append.

Check your understanding

Using PKCS#7 with a 16-byte block size, how much padding does a 32-byte (block-aligned) message get?

  • A. 0 bytes — it already fills whole blocks, so no padding is needed.
  • B. 16 bytes — a full extra block, each byte equal to 0x10. (correct)
  • C. Pad to the next block with 1 bits until it's full, then stop.
  • D. 8 bytes, each equal to 0x08, to half-fill a new block.

Answer: B

Why: §6.8 / RFC 5652: PKCS#7 always appends 1–16 bytes, never 0. When the message is already block-aligned, it appends a WHOLE new block — 16 bytes each holding the value 16 (0x10) — so the receiver always reads the last byte as the pad count and strips exactly that many. Depad here reads 0x10 = 16 and removes 16 bytes, recovering the original 32.

Why A tempts people
If you append 0 bytes, depadding is ambiguous: a real final byte could be mistaken for a pad count. PKCS#7 forbids this by always adding a full block when aligned.
Why C tempts people
Padding with all 1s is exactly the ambiguous scheme PKCS#7 was designed to avoid — the receiver can't tell how many 1 bits were padding versus message.
Why D tempts people
The pad count must reach the NEXT block boundary from the current length. An aligned message needs a full 16-byte block, not a half-block of 0x08.

80. Misconceptions to retire

Concept

81. Synthesis — where IND-CPA is won or lost

Concept

82. Primary sources & where to read more

Concept

83. Connect it up: L21 · Padding (PKCS#7), Parallelization Trade-offs & IV Reuse

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — Why CBC Needs Padding · PKCS#7: Unambiguous Padding · Why CTR Needs No Padding · The Danger of IV Reuse · Choosing a Mode: CBC vs CTR. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

84. Recap — Lesson 21

Recap

You can now explain why CBC needs padding and CTR doesn't, apply PKCS#7 (including the block-aligned full-block case), rank IV-reuse severity across CTR and CBC, and read the CBC-vs-CTR table to choose a mode.

Idea§The one-line version
CBC needs padding6.8Short last block ⇒ ⊕ and cipher input undefined
PKCS#76.8Append N bytes of value N; depad reads the last byte
Aligned edge case6.8Already aligned ⇒ append a full 16-byte 0x10 block
CTR needs no padding6.8Keystream is trimmable; ciphertext = plaintext length
CTR IV reuse6.9Two-time pad: C ⊕ C′ = M ⊕ M′ (catastrophic)
CBC IV reuse6.9Only a shared-prefix leak (contained)
Fresh IV rule6.9Always fresh, random, unpredictable — never constant
CBC vs CTR6.7CTR: parallel + no pad but needs unique nonces

Sources

  1. CS 161 Computer Security Textbook §6.7–6.9 — Wagner, Weaver, Kao, Shakir, Law & Ngai, UC Berkeley — block-cipher modes, the parallelizability trade-off (§6.7), PKCS#7 padding for CBC and why CTR needs none (§6.8), and the severity of IV/nonce reuse in CBC vs CTR (§6.9)
  2. RFC 5652 — Cryptographic Message Syntax (CMS), §6.3 Content-encryption Process — Housley, IETF, 2009 — the canonical statement of PKCS#7 padding: pad with N bytes each of value N, and append a full block when the input is already block-aligned
  3. NIST SP 800-38A — Recommendation for Block Cipher Modes of Operation — Dworkin, NIST, 2001 — defines CBC and CTR (Appendix B/C); CBC requires an unpredictable IV, and the CTR counter blocks must be unique across all messages under one key
  4. Intercepting Mobile Communications: The Insecurity of 802.11 — N. Borisov, I. Goldberg & D. Wagner, MobiCom 2001 — the WEP break: a 24-bit IV reused on a busy network turns RC4 into a repeated keystream, exactly the CTR-style nonce-reuse failure

Want this taught 1-on-1? Alexander tutors Computer Security — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108