Assignment #1 - AES ECB

Deadline: 22.10.2024 23:59:59 Brno time
Points: 10 points
Responsible contact: Ján Jančár <445358@mail.muni.cz>

ECB (Electronic Codebook) mode is an encryption mode for block ciphers which encrypts each plaintext block independently. It requires that the input length is a multiple of the block size. An important property of ECB is that when a plaintext block repeats the corresponding ciphertext blocks also repeat.

Diagram of ECB mode encryption.
Diagram of ECB mode encryption.

Task

You will have access to an ECB encryption function using the AES block cipher (running on our server) in which your input is prepended to a secret message, this data is then zero-padded on the right to the closest multiple of AES block length. Your goal is to obtain the secret message that is appended to your data before it is encrypted. This secret message consists of four English words separated by spaces (i.e. characters matching the regular expression [a-z ] in ASCII). The padding is the zero byte, not the ASCII value for the character zero.

AES

AES is a block cipher with block length of 16 bytes (or 128 bits). There are three variants of AES:

where the 128, 192 and 256 refer to the size of the key used (not to the block length, which is constant at 128 for all AES variants). This task uses AES-128, but that is not really important for the solution.

Your goal is not to break AES, it is a well-designed block cipher!

Example

The following is a Python code example which implements the encryption on the side of the server.

# Uses the pycryptodome package.
from Crypto.Cipher import AES
KEY = b"..."
SECRET = b"..."
def encrypt(data):
    # Create a cipher object.
    cipher = AES.new(key=KEY, mode=AES.MODE_ECB)
    # Pad the plaintext at the end with \x00 so that it is a multiple of AES block size.
    if len(data + SECRET) % AES.block_size != 0:
        pad = b"\0" * (AES.block_size - (len(data + SECRET) % AES.block_size))
    else:
        pad = b""
    padded = data + SECRET + pad
    # Encrypt the padded message
    encrypted = cipher.encrypt(padded)
    return encrypted

Hint

An interesting aspect of AES-ECB is that the adversary can detect when two or more plaintext blocks are the same, just by looking at ciphertext blocks, since the ciphertext blocks will also be the same. During this task you will work and obtain the plaintext secret byte-by-byte.

API

The API consists of two endpoints: a test one for testing out your solution which gives you the plaintext with the secret as well, and an encrypt endpoint which uses the real secret (and a different key).

Don't forget to use the encrypt endpoint to obtain the final solution!

You can find a minimal working example of interacting with the endpoints in Python here.

Test
Request

Encrypt the plaintext using a test key.

Path: /hw01/test/<uco>/
Method: POST
Body: JSON (application/json) dictionary with one key "data" containing a hexadecimal plaintext message.
Response

JSON dictionary with two keys: "ciphertext" containing a hexadecimal-encoded ciphertext and "plaintext" containing a hexadecimal-encoded plaintext message (with the secret message appended and padded).

Encrypt
Request

Encrypt the plaintext using the real key.

Path: /hw01/encrypt/<uco>/
Method: POST
Body: JSON (application/json) dictionary with one key "data" containing a hexadecimal plaintext message.
Response

JSON dictionary with one key: "ciphertext" containing a hexadecimal-encoded ciphertext.

Submission

You should submit a zip-file containing three things:

Grading

The recovery of the correct secret message is worth 7 points, with the description worth the remaining 3 points. However, a submission with just the secret message and no description is worth 0 points. Not conforming to the above format of the solution leads to a -0.5 point penalty.