Don't like this style? Click here to change it! blue.css
The goal of this section is to give you a tangible way to recognize the problem with ECB mode. We're going to encrypt an image and hopefully see what looks like white noise. I promise that this will feel satisfying.
We are going to play with some very useful tools today in order to do something which you should never do. You will learn a lot and we'll analyze it next time. Here is the goal: Encrypt this image with AES ECB mode.
Your output will look like this:
Of course that has leaked some information about your image. This is a warning of incorrect ways to use the correct tools.
We've started to learn about Block Ciphers which take in k-bytes and return k-bytes encrypted. Typically this is 128-bits as a time.
You can't store a lot of words into 128-bits (that's just 16 ascii characters).
So when your message is longer than what your block cipher can handle we need to use a mode of operation . What that really means is a way of dealing with chunks of more than 128 bits.
The straw-man mode is just encrypt each 128-bit chunk with the same key 16 bytes at a time. That mode is called Electronic Code Book (ECB) mode and it's our goal on this page.
We will use Python Image Library (PIL), PyCrypto, and hashlib
from PIL import Image
from Crypto import Random
from Crypto.Cipher import AES
im = Image.open('heckert_gnu.png')
Image Tasks Part 1: so your goal is to read in the rawbytes of the image, the image "mode", and the image size (as a tuple).
Encryption Task: Now we have to encrypt a string of bytes. We will use the current state-of-the-art Block cipher, AES, but in ECB mode. The output bytes should be just as long as the input bytes.
To do this encryption you'll want to generate
AES.block_size bytes of random data as the IV (initial vector) (
I also recommend using SHA256 digest from a 'password' to get a key of 32 bytes.
Finally when you build your cipher you can get the mode as
Create Image from noise bytes: Finally we want to use that mode and size from earlier to build a new image using the PIL library like this:
Image.frombytes(image_mode, image_size, encrypted_bytes).save('output.png') .
Extra Credit: Switch to CTR mode and observe the difference.
So block ciphers only work on a fixed number of bytes and ECB mode won't do. Chained Block Cipher mode is our first reasonable mode. It also shows the basics of how these "modes" work.
Let's do it by hand and confirm that we agree with PyCrypto.
The first step is to generate a random IV of 16 bytes.
Then XOR the IV and the first 16 bytes of your plaintext to get input for AES.
That creates the first 16 bytes of the cipher text (often the IV is sent as the actual first 16 bytes like our NONCE example in the stream-cipher lesson). These first computed cipher bytes become the IV for round 2.
CBC via Library: Using the secret key "andy love simone" (16 characters/bytes) and IV from the 16-byte hexdigest "000102030405060708090a0b0c0d0e0f" then the encryption of "abcdefghijklmnopqrstuvwxyzabcdef" (32 bytes) is "87dd2acb714db44393d8b4b71bdbad7720fbf40d2e34a03a93324cb9c4b97a08" (32 bytes). Confirm this using PyCrypto.
CBC by hand: Now recompute this number using the IV, XOR, and individual runs of the block cipher (one block at a time) with my secret key.
Decrypt both ways: Now use the library to decrypt the above message then decrypt by hand. (Decrypting CBC by hand requires computing XOR(previous_cipher_block, AEScipher.decrypt(this_cipher_block)))
Someone messed with my screenshot, help me figure out what it says:
There is a subtle flaw in CBC when it is chained. This is a real-world risk that you should be aware of as you go forward.
OK, a pop-quiz for you. (This quiz is a weakness you can exploit in SSL 3.0 and TLS 1.0 if you're keen to.)
This challenge is centered around stateful CBC mode (I call it chained CBC mode), in which the cipher attempts to save bandwidth by using the previous cipher block as the next IV. If you encrypt message chunks \(m_1, m_2, m_3\) in pure (and secure) CBC mode or just ask to encrypt \(m_1\) then ask for \(m_2\) then ask for \(m_3\) the result will be identical. But if you pick a clever \(m_2\) then you should learn something about \(m_1\).
I give you this quiz for two main reasons:
OK, the chained CBC class will remember it's IV. The first time it is called it is random and after that it is the result of AES on the previous input.
The challenge class will randomly select one of two 16-byte messages and encrypt it using a ChainedCBC cipher. The challenge will let you encrypt more plaintext of your choosing as part of your attack. When you think you know which message you got call the method
yourchallenge.isTheSecret(yourguess) and determine if you got it right or wrong. Run your winning algorithm on many inputs to see if you've done better than 50/50.
Here is the challenge code: