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 task
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 usebytes.fromhex()
to build a hex byte array.
- Hint: Convert s to a hexadecimal string using
- 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
- 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.)
- Take a look at the pycrypto api. It includes an implementation of AES.
Hints
- 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()
- Note that
recv(num_bytes)
will receive at mostnum_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…) - 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. - 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.
- RFC 3526 specifies the following values for p and g:
p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF g = 0x2
- You can convert an integer to a hex string using
hex()
- You can convert a hex string to an integer using
int("0x1a2b34", 16)
- You can convert a hex string to a byte array using
bytes.fromhex("1a2b34")
(Python 3) or"1a2b34".decode("hex")
(Python 2) - Need to generate some random bits? Check out
getrandbits
in Python. - Need to do modular exponentiation? Checkout
pow
in Python.