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.
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 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.
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
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.
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).
You can find a minimal working example of interacting with the endpoints in Python here.
Encrypt the plaintext using a test key.
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 the plaintext using the real key.
JSON dictionary with one key: "ciphertext" containing a hexadecimal-encoded ciphertext.
You should submit a zip-file containing three things:
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.