C 202: ECB v. CBC Modes with Python 3 (10 pts + 20 extra)

What you need:

Purpose

To use AES in Electronic Code Book (ECB) mode, see it fail to remove patterns from an image, and demonstrate that Cipher Block Chaining (CBC) is better.

Download Image

Right-click the penguin image on the right side of this page and save it somewhere you can find it, such as in your Downloads folder.

The image is named "tux.bmp" and I got it from Wikipedia.

Installing pip and pycryptodome

If you are using a Debian Linux system, execute these commands from a Bash prompt:
sudo apt update
sudo apt install python3-pip -y
python3 -m pip install pycryptodome

Opening Python

Open a Terminal or Command Prompt window and execute these commands:
cd Downloads
python3
Python 3 opens in Immediate Mode, as shown below.

Encrypting the Image in ECB Mode

Execute these commands to import the AES functions and create a new "cipher" object.
from Crypto.Cipher import AES
key = b"aaaabbbbccccdddd"
cipher = AES.new(key, AES.MODE_ECB)

Execute these commands to read the "tux.bmp" binary file into a variable named "clear". After the second line, press Enter twice.

with open("tux.bmp", "rb") as f:
  clear = f.read()
  

Execute this command to encrypt the data in "clear".

ciphertext = cipher.encrypt(clear)
An error message appears, saying "Data must be aligned to block boundary in ECB mode", as shown below.

Execute these commands to see the length of the "clear" data, and the length modulus 16.

len(clear)
len(clear)%16
As shown below, the length mod 16 is 2.

Execute this command to trim a section of "clear" out, skipping the first 64 bytes (the image file header), and the last 2 bytes, saving the result in a variable named "clear_trimmed".

clear_trimmed = clear[64:-2]

Execute these commands to see the length of the "clear_trimmed" data, and the length modulus 16.

len(clear_trimmed)
len(clear_trimmed)%16
As shown below, the length mod 16 is 0. It's now a multiple of 16 bytes long.

Execute this command to encrypt the data in "clear_trimmed", and put it in a variable named "ciphertext".

ciphertext = cipher.encrypt(clear_trimmed)

Execute these commands to add the first 64 bytes and the last 2 bytes to "ciphertext", and write it to a file named "tux_ecb.bmp".

After the third line, press Enter twice.

ciphertext = clear[0:64] + ciphertext + clear[-2:]
with open("tux_ecb.bmp", "wb") as f:
  f.write(ciphertext)
  

Viewing the Encrypted File

In a file browser, navigate to your Downloads folder and double-click the "tux_ecb.bmp" file, as shown below.

The encrypted file still shows a lot of information about the image, as shown below.

Viewing the End of the File in Hex

Execute these commands to read the "tux_ecb.bmp" binary file into a variable named "clear". After the second line, press Enter twice.
with open("tux_ecb.bmp", "rb") as f:
  bytes = f.read()
  

C 202.1: Hexadecimal Values (10 pts)

Execute this command to show the last four bytes of the encrypted file in hexadecimal.
bytes[-4:].hex()
The flag is covered by a green rectangle in the image below.

Encrypting the Image in CBC Mode

Execute these commands to create a new "cipher" object in CBC mode.

CBC mode requires an additional "iv" parameter, as shown below.

iv = b"0000111122223333"
cipher = AES.new(key, AES.MODE_CBC, iv)

Execute this command to encrypt the data in "clear_trimmed", and put it in a variable named "ciphertext".

ciphertext = cipher.encrypt(clear_trimmed)

Execute these commands to add the first 64 bytes and the last 2 bytes to "ciphertext", and write it to a file named "tux_cbc.bmp".

After the third line, press Enter twice.

ciphertext = clear[0:64] + ciphertext + clear[-2:]
with open("tux_cbc.bmp", "wb") as f:
  f.write(ciphertext)
  

Viewing the Encrypted File

In a file browser, navigate to your Downloads folder and double-click the "tux_cbc.bmp" file.

The encrypted file is now random pixels, as shown below.

Viewing the End of the File in Hex

Execute these commands to read the "tux_cbc.bmp" binary file into a variable named "clear". After the second line, press Enter twice.
with open("tux_cbc.bmp", "rb") as f:
  bytes = f.read()
  

C 202.2: Hexadecimal Values (10 pts)

Execute this command to show the last four bytes of the encrypted file in hexadecimal.
bytes[-4:].hex()
The flag is covered by a green rectangle in the image below.

Encrypting the Image in GCM Mode

Because of the Padding Oracle attacks, CBC mode has fallen into disfavor. The modern recommended mode is Galois Counter Mode (GCM).

Execute these commands to create a new "cipher" object in GCM mode.

iv = b"0000111122223333"
cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
Execute this command to encrypt the data in "clear_trimmed", and put it in a variable named "ciphertext".
ciphertext = cipher.encrypt(clear_trimmed)
Execute these commands to add the first 64 bytes and the last 2 bytes to "ciphertext", and write it to a file named "tux_gcm.bmp".

After the third line, press Enter twice.

ciphertext = clear[0:64] + ciphertext + clear[-2:]
with open("tux_gcm.bmp", "wb") as f:
  f.write(ciphertext)
  

Viewing the Encrypted File

In a file browser, navigate to your Downloads folder and double-click the "tux_gcm.bmp" file.

The encrypted file is now random pixels, as shown below.

Viewing the End of the File in Hex

Execute these commands to read the "tux_gcm.bmp" binary file into a variable named "clear". After the second line, press Enter twice.
with open("tux_gcm.bmp", "rb") as f:
  bytes = f.read()
  

C 202.3: Hexadecimal Values (10 pts)

Execute this command to show the last four bytes of the encrypted file in hexadecimal.
bytes[-4:].hex()
The flag is covered by a green rectangle in the image below.


Posted 9-17-17 by Sam Bowne
Revised 10-16-17
Added to Crypto Hero 4-15-18 9 pm
Windows instructions added 3-5-19
Modified for new scoring engine 7-6-19
Extra credit points specified 9-10-20
Ported to Python 3 9-17-20
pycryptodome steps added 10-8-20
pycryptodome steps moved to the beginning 11-6-21