This shows you the differences between two versions of the page.
ac:laboratoare:04 [2018/10/16 14:34] tiberiu.iorgulescu |
ac:laboratoare:04 [2022/10/27 15:58] (current) marios.choudary |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ===== Lab 04 - Public Key Encryption ===== | ||
+ | |||
+ | Before starting the labs, download openssl 1.1.1 from [[https://www.openssl.org/source/openssl-1.1.1q.tar.gz|here]]. | ||
+ | Save the file to some local folder accessible by you, then compile it and install it to some folder. | ||
+ | Open the unpacked folder from bash, and run the following commands: | ||
+ | <code bash> | ||
+ | linux$ ./config --prefix=/home/student/local --openssldir=/home/student/local/openssl | ||
+ | linux$ make | ||
+ | linux$ make test | ||
+ | linux$ make install | ||
+ | </code> | ||
+ | (in case of trouble, check also the instructions at the end of [[https://ocw.cs.pub.ro/courses/sasc/laboratoare/08|this lab]]). | ||
+ | |||
+ | /* While the tools are building/compiling you may start working on some of the exercises. */ | ||
+ | |||
<hidden> | <hidden> | ||
- | ===== Lab 04 - MACs, Hashes, OpenSSL ===== | + | ==== Exercise 1: Birthday Attack (3p) ==== |
- | ==== Exercise 1 ==== | + | In this exercise you will implement the Birthday attack on SHA-1. The goal is to obtain a collision in the first four bytes of the hash. |
- | In this first exercise we'll see how to compute hashes using the OpenSSL command line interface. | + | You can start from this code: |
- | You can interact with the OpenSSL utilities in two ways: | + | <code birthday.py> |
- | * directly from bash, by using the ''openssl'' command followed by the desired command and parameters | + | import hashlib |
- | * from the OpenSSL console, by using the ''openssl'' command without additional arguments. You can close the console by calling ''quit'' or ''exit''. | + | import random |
- | If the manual pages are correctly installed, you can consult the documentation via ''man <command_name>'' (e.g. ''man md5''). | + | N_MESSAGES = 2**16 # 2^16 random messages |
+ | N_COLL_BYTES = 4 | ||
+ | def generate_messages(): | ||
+ | msgs = [] | ||
+ | | ||
+ | for i in xrange(N_MESSAGES): | ||
+ | msgs.append("Ana are %d mere si %d pere" % (i, random.randint(0, 100000))) | ||
- | Hashes are often used to check the integrity of downloaded files. We will now use OpenSSL to compute the MD5 and SHA-1 hashes of this page. | + | return msgs |
- | Download this page by running: | + | def find_collision(msgs): |
+ | hashes = dict() # will keep first N_COLL_BYTES bytes of each hash | ||
- | <code> | + | # TODO - find collision and return it as a tuple (msg1, msg2) |
- | linux$ wget http://ocw.cs.pub.ro/courses/sasc/laboratoare/09 -O sasc.html | + | |
+ | return None # return None if no collision is found | ||
+ | |||
+ | def main(): | ||
+ | while True: | ||
+ | # Generate N_MESSAGES (2^16) different random messages | ||
+ | msgs = generate_messages() | ||
+ | |||
+ | # Find a hash collision | ||
+ | collision = find_collision(msgs) # collision = (msg1, msg2) | ||
+ | |||
+ | if collision: | ||
+ | # print collision (the two messages and their hash) in a readable format | ||
+ | print collision[0] # msg1 | ||
+ | print hashlib.sha1(collision[0]).hexdigest() # msg1 hash | ||
+ | print collision[1] # msg2 | ||
+ | print hashlib.sha1(collision[1]).hexdigest() # msg2 hash | ||
+ | break | ||
+ | |||
+ | if __name__ == '__main__': | ||
+ | main() | ||
</code> | </code> | ||
+ | Can you also find a collision in the first 5 bytes of the hash? | ||
- | Use OpenSSL to compute the MD5 and SHA-1 hashes of the newly downloaded file; print the output in hexadecimal. | + | <note>In order to compute a SHA-1 hash, you can use the hashlib module: |
+ | <code>hashlib.sha1(msg).hexdigest()</code> | ||
+ | </note> | ||
- | To check your results, you can use ''md5sum'' or ''sha1sum'' as an alternative way of computing the same hashes. | + | ==== Exercise 2: RSA parity oracle (4p) ==== |
- | ==== Exercise 2 ==== | + | Generate a 1024 bit RSA key pair. |
- | In this second exercise we'll use the command line to compute an HMAC, with SHA-1 as the hashing algorithm. | + | Write an oracle function that uses the private key to answer the question "is the plaintext of this message even or odd" (is the last bit of the message 0 or 1). Imagine for instance a server that accepted RSA-encrypted messages and checked the parity of their decryption to validate them, and spat out an error if they were of the wrong parity. |
- | Recall from the lecture that for HMAC to be secure, we need to sample a random key $k \gets \mathcal{K}$. | + | Anyways: function returning true or false based on whether the decrypted plaintext was even or odd, and nothing else. |
- | We can generate random bytes using ''openssl rand''. To compute HMACs, check the documentation for ''openssl dgst''. | + | Take the following string and un-Base64 it in your code (without looking at it!) and encrypt it to the public key, creating a ciphertext: |
+ | <note> | ||
+ | VGhhdCdzIHdoeSBJIGZvdW5kIHlvdSBkb24ndCBwbGF5IGFyb3VuZCB3aXRoIHRoZSBGdW5reSBDb2xkIE1lZGluYQ== | ||
+ | </note> | ||
- | For this exercise, use OpenSSL commands to: | + | With your oracle function, you can trivially decrypt the message. |
- | - generate a 16 byte random key | + | |
- | - use the key to compute the SHA-1 HMAC of the page downloaded in the previous exercise | + | |
+ | Here's why: | ||
+ | * RSA ciphertexts are just numbers. You can do trivial math on them. You can for instance multiply a ciphertext by the RSA-encryption of another number; the corresponding plaintext will be the product of those two numbers. | ||
+ | * If you double a ciphertext (multiply it by (2**e)%n), the resulting plaintext will be either even or odd, depending on whether the multiplication result was larger than the modulus or not. | ||
+ | * If the plaintext after doubling is even, doubling the plaintext didn't wrap the modulus --- the modulus is a prime number. | ||
- | ==== Exercise 3 ==== | + | That means the plaintext is less than half the modulus. |
- | In this exercise you will implement the Birthday attack on SHA-1 from the previous lab using OpenSSL. The goal is to obtain a collision in the first four bytes of the hash. | + | You can repeatedly apply this heuristic, once per bit of the message, checking your oracle function each time. |
- | In contrast to previous labs, this time we'll use C. You can implement the attack from scratch, or start from our {{:sasc:laboratoare:birthday.tar.gz|archive here}}. | + | Your decryption function starts with bounds for the plaintext of [0,n]. |
- | To compute a digest, you might find the code below useful: | + | Each iteration of the decryption cuts the bounds in half; either the upper bound is reduced by half, or the lower bound is. |
- | <code C> | + | After log2(n) iterations, you have the decryption of the message. |
- | SHA_CTX context; | + | |
- | SHA1_Init(&context); | + | |
- | SHA1_Update(&context, buffer, length); | + | |
- | SHA1_Final(md, &context); /* md must point to at least 20 bytes of valid memory */ | + | |
- | </code> | + | |
- | <note important> | + | Print the upper bound of the message as a string at each iteration; you'll see the message decrypt "hollywood style". |
- | To compile using OpenSSL you will need to install the development version of the library which includes the header files. | + | |
- | Download the library from https://www.openssl.org/source/old/1.0.1/openssl-1.0.1f.tar.gz, and unpack it. | + | Decrypt the string (after encrypting it to a hidden private key) above. |
- | Open the unpacked folder from bash, and run the following commands: | + | {{:ic:laboratoare:parity_oracle.zip}} |
- | <code bash> | + | |
- | linux$ ./config --prefix=/home/student/local --openssldir=/home/student/local/openssl | + | |
- | linux$ make | + | |
- | linux$ make install_sw | + | |
- | </code> | + | |
- | To fix the makefile using the new paths, change the variables at the start with the ones below: | + | </hidden> |
- | <code makefile> | + | |
- | LDFLAGS=-L/home/student/local/lib -lcrypto | + | ==== Exercise 1: Diffie Hellman (8p + 2p) ==== |
- | CFLAGS=-Wall -g -I/home/student/local/include | + | |
- | </code> | + | As we discussed in class, Diffie and Hellman proposed the first public key exchange mechanism such that |
+ | two parties, that did not share any previous secret could establish a common secret. This allows | ||
+ | the parties to have a shared key that only they know (except if there is an active man in the middle attack, | ||
+ | which is usually solved by using TLS/certificates, but we shall not focus on that here). | ||
+ | |||
+ | Download the lab code from {{:ac:laboratoare:lab_dhe.zip|here}}. After unzipping, you'll find the source code | ||
+ | for a client (dhe.c) and a server (dhe_server.c), along with a Makefile and fixed Diffie-Hellman p and g params in the files dhparam.pem. | ||
+ | |||
+ | <note> | ||
+ | Update the Makefile with the paths relevant to your installation folders if you didn't use /home/student/local as installation place for openssl. | ||
</note> | </note> | ||
+ | |||
+ | The client and server have a similar structure. Each of them should build a public key, then send it to the other party, receive the public key from the other party and finally compute the secret key. Your task is to complete the missing parts. For this, consult the openssl documentation [[https://www.openssl.org/docs/man1.1.1/man3/|here]]. Since the client and server are similar, focus only on one of them and then do similarly on the other one. | ||
+ | |||
+ | The makefile should help you build both. Just type 'make all'. | ||
+ | After completing the necessary todo's in the file, you can start the server by typing 'make start_server' and the | ||
+ | client with 'make start_client'. | ||
+ | |||
+ | If all goes well, you should see the same secret key on both client and server. | ||
+ | |||
+ | <hidden> | ||
+ | The solution is {{:ic:laboratoare:lab_dhe_solved.zip|here}}. | ||
</hidden> | </hidden> | ||
+ | |||
+ | === Bonus 1 === | ||
+ | |||
+ | Perform the DH key exchange between two teams, sending the public key values over the network and verify that you get the same secret key. | ||
+ | |||
+ | === Bonus 2 === | ||
+ | |||
+ | Use the secret key to encrypt some data and check that the other party can decrypt it. You can use | ||
+ | the code available [[https://paste.ubuntu.com/p/4XZpMtt9ZZ/ | here]]. |