$$$$## Project 4
Meet in the middle attack
In this project we will do a meet in the middle attack on 2DES. The idea of a meet in the middle attack is discussed in the textbook in Chapter 5. A description in pseudocode can be found below.
As you may recall from reading the book and from our discussions in class, the MITM attack on 2DES requires CPU operations, and a database with rows. Naturally we don't actually have those computational resources. To make the project possible we will use a version of DES that has a 21 bit key. We do this by making most of the key bits zero and only allowing 21 of them to vary. This cipher has the following code.
The code makes use of des56.h
, which we also used in Project 3. The function takes as input a plaintext block pt
which is constant (not modified by the function). It also takes a ciphertext block ct
which is modified so as to contain the ciphertext, an encrypt/decrypt flag called decrypt
and a 3 byte key. Note that 3 bytes of memory is actually 24 bits, but because DES discards every 8th bit, only 21 of the bits are functional. Because every 8th bit is tossed out in the key, there is no reason to consider key bytes which are odd numbers.
With the DES_21_bit_key
function serving as a DES substitute, we can define 2DES as follows.
The above function takes a block as input, as well as an encrypt/decrypt flag and two independent keys. It simply calls our DES substitute twice, once with each key. For decryption the order of the keys is reversed. The block of input is modified so as to contain the resulting ciphertext (or decrypt, depending on the value of the decrypt
parameter).
In this project there is a piece of ciphertext we would like to decrypt, namely the following.
Fortunately we have a known-plaintext pair , where and the key is the same as the one used to produce the target ciphertext. The pair is:
Expanding the template code in template.cpp
, your job is to complete the MITM attack by implementing the following pseudocode description.
On cocalc each loop should require about 10 seconds. Note that if we were using a brute force approach, the time required would be seconds, which is about 242 days. Thus the MITM strategy is helping considerably.
Using the STL map data structure
We will use the C++ map
datatype to store the association between intermediate blocks z
and the keys that give rise to them (please see the above pseudocode for the meaning of z
).
One difficulty is that our blocks and our keys are char
arrays. While it is possible to use these with a map
it will be more convenient to use vector
types. Fortunately char
arrays are easily converted into vectors, as shown below.
In the above code K
will be the vector representation of the key key1
and Z
will be the vector representation of z
. This constructor makes a copy, so you do not need to worry about changes to z
affecting Z
, for example.
Now we can easily associate these objects by using a map
:
Another key part of the pseudocode (no pun intended) involves determining whether M[Z]
is defined. That is, we want to know if an assignment of the form M[Z]=K
has ever been made for a particular Z
. One approach to doing this is the following:
The inner part of the above conditional will execute exactly if M[Z]
has already been defined. You can extract the value stored in the iterator L
by using L->second
notation, or just call M[Z]
to get the value.
Incrementing the key
To search through all keys you must find a way to check all even values of the three bytes of a key.
It is sufficient to check even byte values because DES discards every 8th bit, and these are exactly the least significant bits of each byte. You could just use all values, but this will make your code run 8 times slower (please don't do this!).
The way to write this function is as follows. The key should be initialized to have zero in each byte. To go to the "next key" value, first try to increment c
(i.e key[2]
) by 2. If this byte is full then be sure to also increment b
by 2. But if b
is full then be sure to also increment a
by 2. The simplest way to do this is probably using a recursive function.
Testing the result
When your program successfully finds the key, there is a small chance that you found a false key. Check that this is not the case by decrypting the file encryption.des
, located in the same directory as the code. The file is encrypted with 2DES_21 in ECB mode, so be sure to use the same mode when decrypting.
Compiling the code
To compile the code you can use:
To run the resulting program do:
If you're getting an overwhelming number of errors, the following can be useful. It will output only the first 10 lines of error messages.
Working in Python
You are welcome to do this project in Python if you want. For a DES client you might use pycrypto. Obviously you would use the dict
type to store the block/key pairs.