## Lab 5: Diffie-Hellman Wisdom

In this lab you will expand your fortune client from the previous lab to include a Diffie-Hellman key exchange.

Your instructor will provide you with a hostname and port where you can find a fortune server that requires you to perform a Diffie-Hellman key exchange.

When the client first connects to the server, they perform a Diffie-Hellman key exchange in order to agree on a 128-bit symmetric key. Then, the server uses the key to encrypt a fortune (and a flag) with AES in ECB mode, and transmits it to the client. An ordered list of events is as follows:

• The client connects over TCP.
• The server generates a 480-bit value, a.
• The server calculates A using p and g from the 4096 MODP group that can be found in RFC 3526.
• The server sends A to the client. A is formatted as a string representation of a hexadecimal number. It is followed by a newline (\n).
• The client generates a 480-bit value, b.
• The client calculates B using p and g from the 4096 MODP group that can be found in RFC 3526.
• The client sends B to the server. B is formatted as a string representation of a hexadecimal number, similar to how A was received. It is followed by a newline (\n).
• The client and server both calculate s.
• The 128-bit key, k, is the first 16 bytes of s.
• Hint: Convert s to a hexadecimal string using `hex()`, then use `bytes.fromhex()` to build a hex byte array.
• The server generates a random fortune and encrypts it using k. The encryption used is AES in ECB mode. Prior to encryption, the server pads the fortune to ensure its length is a multiple of 16. (You donâ€™t need to do anything with regards to padding.)
• The server sends the ciphertext to the client.

### References

1. Take a look at the socket api for Python. (The link is is for Python 3.6, but you can change the version in the upper left of the page.)
2. Take a look at the pycrypto api. It includes an implementation of AES.

### Hints

1. Socket programming is a big topic, so here is some sample code to open a new connection to a given port, read some bytes, and print them:
``````import socket
sock = socket.create_connection(('rainmaker.wunderground.com', 23))
data = sock.recv(8192)
print(data)
sock.close()
``````
2. Note that `recv(num_bytes)` will receive at most `num_bytes`, but may return less. If you want to make sure you get a specific number of bytes, you may need to build a loop to do so. (Although frequently you are just lucky and get the number of bytes you expectedâ€¦)
3. If you call `recv()` and there is no data available to be read, then it will block and your program will wait until there is data to be read, the connection is closed, or a timeout occurs.
4. When passing a key to the pycrypto library, you should be passing raw bytes. For example, a 128-bit key (16 bytes) should be a 16-byte buffer containing the bytes, not an integer.
5. RFC 3526 specifies the following values for p and g:
``````p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF
g = 0x2
``````
6. You can convert an integer to a hex string using `hex()`
7. You can convert a hex string to an integer using `int("0x1a2b34", 16)`
8. You can convert a hex string to a byte array using `bytes.fromhex("1a2b34")` (Python 3) or `"1a2b34".decode("hex")` (Python 2)
9. Need to generate some random bits? Check out `getrandbits` in Python.
10. Need to do modular exponentiation? Checkout `pow` in Python.