Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ac:laboratoare:04 [2017/09/25 20:56]
dan.dragan
ac:laboratoare:04 [2022/10/27 15:58] (current)
marios.choudary
Line 1: Line 1:
-===== Lab 04 - MACs, Hashes, OpenSSL ​=====+===== Lab 04 - Public Key Encryption ​=====
  
-==== Exercise ​1 - Timing attack ====+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]]).
  
-In this exercise ​you will perform a timing attack against CBC-MAC.+/* While the tools are building/​compiling ​you may start working on some of the exercises*/
  
-You are given access to a CBC-MAC $\mathsf{Verify}$ oracle, which tests whether the received tag matches the one computed using the secret key. Timing attacks exploit naive equality comparisons between the received and computed MACs (for example, the comparison is done byte by byte; more checks means more latency).+<​hidden>​ 
 +==== Exercise 1: Birthday Attack ​(3p====
  
-Your task is to produce ​forged tag for the message '​Hristos a inviat'​ without knowing the key. Do this by iterating through all possible values for a specific byte; when the oracle'​s latency for a certain value seems larger than the rest, it suggests that the equality test returned True and the oracle passed to the next byte.+In this exercise you will implement the Birthday attack on SHA-1. The goal is to obtain ​collision in the first four bytes of the hash.
  
-Try to start by finding the first byte and checking your result with the timing attack.+You can start from this code:
  
-You can use ''​time.clock()''​ before and after each oracle query to measure its runtime. +<code birthday.py> 
- +import ​hashlib
-<note important>​ +
-The oracle'​s latency is subject to noise; for the best results, you may need to run each query multiple times (try 30) and compute the mean latency. +
-</​note>​ +
- +
-TODO1: Implement the CBC-MAC function. +
- +
-<​note>​ +
-To check your implementation of CBC-MAC is correct, verify that this (plaintext,​tag) verifies fine: +
-plaintext = '​Placinta de mere'​ +
-tag = '​07d2771038d62b94fce106cff957da0f' ​ (in hex, you need to apply decode to get a bytestream) +
-</​note>​ +
- +
-TODO2: Implement the MAC time verification attack and obtain the desired MAC without knowing the key. +
- +
-<​note>​ +
-Try to print the resulting tag in hex (with tag.encode(hex)). It should start with 51 and end with 81. +
-</​note>​ +
- +
-<file python timing.py> +
-import ​sys+
 import random import random
-import string 
-import time 
-import itertools 
-import operator 
-import base64 
-  ​ 
-from Crypto.Cipher import AES 
-from Crypto.Hash import SHA256 
  
-def slow_foo():​ +N_MESSAGES ​= 2**16 # 2^16 random messages 
-    p = 181 +N_COLL_BYTES ​4
-    k = 2 +
-    while k < p: +
-        if p % k == 0: +
-            return +
-        k += 1 +
-         +
-def aes_enc(k, m): +
-  """​  +
-  Encrypt a message m with a key k in ECB mode using AES as follows: +
-  c = AES(k, m) +
-   +
-  Args: +
-    m should be a bytestring multiple of 16 bytes (i.e. a sequence of characters such as '​Hello...'​ or '​\x02\x04...'​) +
-    k should be a bytestring of length exactly 16 bytes.+
  
-  Return+def generate_messages()
-    ​The bytestring ciphertext c +    ​msgs = [] 
-  """​ +     
-  aes = AES.new(k+    for i in xrange(N_MESSAGES): 
-  c = aes.encrypt(m)+        msgs.append("Ana are %d mere si %d pere" % (i, random.randint(0,​ 100000)))
  
-  ​return ​c+    ​return ​msgs
  
-def aes_dec(k, c): +def find_collision(msgs): 
-  """​ +    ​hashes ​dict() # will keep first N_COLL_BYTES bytes of each hash
-  Decrypt a ciphertext c with a key k in ECB mode using AES as follows: +
-  m AES(k, c)+
  
-  Args: +    # TODO - find collision and return it as tuple (msg1, msg2)
-    c should be bytestring multiple of 16 bytes (i.e. a sequence of characters such as '​Hello...'​ or '​\x02\x04...'​) +
-    k should be a bytestring of length exactly 16 bytes.+
  
-  Return: +    ​return ​None # return None if no collision is found
-    The bytestring message m +
-  """​ +
-  aes = AES.new(k) +
-  m = aes.decrypt(c) +
-   +
-  ​return ​m+
  
-def aes_enc_cbc(k, m, iv): +def main(): 
-  """​ +    while True
-  Encrypt a message m with a key k in CBC mode using AES as follows+        # Generate N_MESSAGES (2^16) different random messages 
-  ​c ​AES(k, m)+        msgs generate_messages()
  
-  Args: +        # Find a hash collision 
-    m should be a bytestring multiple of 16 bytes (i.e. a sequence of characters such as '​Hello...'​ or '​\x02\x04...'​) +        ​collision = find_collision(msgs) # collision = (msg1, msg2)
-    k should be a bytestring of length exactly 16 bytes. +
-    iv should be a bytestring of length exactly 16 bytes.+
  
-  Return+        if collision
-    The bytestring ciphertext c +            # print collision (the two messages and their hash) in a readable format 
-  """​ +            print collision[0] # msg1 
-  aes = AES.new(k, AES.MODE_CBC, iv+            print hashlib.sha1(collision[0]).hexdigest(# msg1 hash 
-  c = aes.encrypt(m)+            print collision[1] # msg2 
 +            print hashlib.sha1(collision[1]).hexdigest() # msg2 hash 
 +            break
  
-  return c+if __name__ == '​__main__':​ 
 +    main() 
 +</​code>​
  
-def aes_dec_cbc(k,​ c, iv): +Can you also find collision ​in the first 5 bytes of the hash?
-  """​ +
-  Decrypt ​ciphertext c with a key k in CBC mode using AES as follows: +
-  m = AES(k, c)+
  
-  Args+<​note>​In order to compute a SHA-1 hash, you can use the hashlib module
-    c should be a bytestring multiple of 16 bytes (i.e. a sequence of characters such as '​Hello...'​ or '​\x02\x04...'​+<​code>​hashlib.sha1(msg).hexdigest()</​code>​ 
-    k should be a bytestring of length exactly 16 bytes. +</​note>​
-    iv should be a bytestring of length exactly 16 bytes.+
  
-  Return: +==== Exercise 2: RSA parity oracle ​(4p====
-    The bytestring message m +
-  """​ +
-  aes AES.new(k, AES.MODE_CBC,​ iv) +
-  m aes.decrypt(c)+
  
-  return m +Generate ​1024 bit RSA key pair.
-   +
-def aes_cbc_mac(k,​ m): +
-  """​ +
-  Compute a CBC-MAC of message m with a key k using AES as follows: +
-  t = AES-CBC-MAC(k=(k1,​k2),​ m), +
-  where k1 is used for the raw-CBC operation and k2 is used for the final +
-  encryption.+
  
-  k1 and k2 are derived from k as follows: +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.
-  [k1|k2] = SHA256(k | "CBC MAC keys")+
  
-  Note: the IV for CBC in this case will be 0.+Anywaysfunction returning true or false based on whether ​the decrypted plaintext was even or odd, and nothing else.
  
-  Args: +Take the following string and un-Base64 it in your code (without looking at it!) and encrypt it to the public key, creating ​ciphertext: 
-    m should be a bytestring multiple of 16 bytes (i.e. sequence of characters such as '​Hello...'​ or '​\x02\x04...'​) +<​note>​ 
-    k should be a bytestring of length exactly 16 bytes.+VGhhdCdzIHdoeSBJIGZvdW5kIHlvdSBkb24ndCBwbGF5IGFyb3VuZCB3aXRoIHRoZSBGdW5reSBDb2xkIE1lZGluYQ== 
 +</​note>​
  
-  Return: + With your oracle functionyou can trivially decrypt the message.
-    The bytestring MAC tof 16 bytes. +
-  """​+
  
-  #Require good size +Here's why: 
-  ​m = m.ljust(16+  ​* RSA ciphertexts are just numbersYou 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. 
-  ​k = k.ljust(16)+  * 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.
  
-  #​Derive ​the keys for raw-CBC and for the final tag +That means the plaintext is less than half the modulus.
-  #[k1 | k2] = SHA256(k + "CBC MAC keys")+
  
-  #Get the MAC: +You can repeatedly apply this heuristiconce per bit of the messagechecking your oracle function each time.
-  #1 - Do aes-CBC with k1 and iv=0then keep only last block (last 16 bytes) ​of encryption +
-  #2 - Perform another AES encryption (simplewithout CBC) on the last block from #1 using k2 +
-  #t = tag +
-  t = 16*'​\x00'​+
  
-  return t+Your decryption function starts with bounds for the plaintext of [0,n].
  
-def verify(messagetag): +Each iteration of the decryption cuts the bounds in half; either the upper bound is reduced by halfor the lower bound is.
-  key = '​Cozonace si oua '+
  
-  # Get correct tag +After log2(n) iterationsyou have the decryption of the message.
-  goodtag = aes_cbc_mac(key, message+
-   +
-  # Compare tags +
-  for i in range(16):​ +
-    # Artificially extend byte comparison duration +
-    slow_foo() +
-    if tag[i] != goodtag[i]:​ +
-      return False+
  
-  return True+Print the upper bound of the message as a string at each iteration; you'll see the message decrypt "​hollywood style"​.
  
 +Decrypt the string (after encrypting it to a hidden private key) above.
  
-def main(): +{{:ic:​laboratoare:​parity_oracle.zip}}
-  message = '​Hristos a inviat'​+
  
-  # Step 1. Iterate through all possible first byte values, and call the +</​hidden>​
-  # Verify oracle for each of them +
-  tag = 16*'​\x00'​ +
-  verify(message,​ tag)+
  
-  # Step 2. Store the byte that caused the longest computation time+==== Exercise 1: Diffie Hellman (8p + 2p) ====
  
-  # Step 3Continue ​the operation for each byte (except the last)+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 secretThis 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).
  
-  # Step 4. Guess the last byteand query the oracle with the complete tag +Download ​the lab code from {{:​ac:​laboratoare:​lab_dhe.zip|here}}. After unzippingyou'll find the source code 
-  mytag = '???'​ +for a client ​(dhe.cand a server (dhe_server.c),​ along with a Makefile and fixed Diffie-Hellman p and g params in the files dhparam.pem.
-  result = verify(message, mytag) +
-  if result == True: +
-    print "Found tag: " + mytag+
  
-if __name__ == "​__main__":​ +<​note>​ 
-  ​main() +Update the Makefile with the paths relevant to your installation folders if you didn't use /​home/​student/​local as installation place for openssl. 
-</file>+</note>
  
-==== Exercise 2 ====+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.
  
-In this first exercise we'll see how to compute hashes using the OpenSSL command line interface.+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'​.
  
-You can interact with the OpenSSL utilities in two ways: +If all goes wellyou should see the same secret key on both client ​and server.
-  * directly from bashby using the ''​openssl''​ command followed by the desired command ​and parameters +
-  * from the OpenSSL console, by using the ''​openssl''​ command without additional arguments. You can close the console by calling ''​quit''​ or ''​exit''​.+
  
-If the manual pages are correctly installed, you can consult the documentation via ''​man ​<command_name>''​ (e.g. ''​man md5''​).+<hidden> 
 +The solution is {{:​ic:​laboratoare:​lab_dhe_solved.zip|here}}. 
 +</​hidden>​
  
 +=== Bonus 1 ===
  
-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.+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.
  
-Download this page by running:+=== Bonus 2 ===
  
-<​code>​ +Use the secret key to encrypt some data and check that the other party can decrypt it. You can use 
-linux$ wget http://​ocw.cs.pub.ro/​courses/​sasc/​laboratoare/​09 -O sasc.html +the code available [[https://paste.ubuntu.com/p/4XZpMtt9ZZ| here]].
-</​code>​ +
- +
- +
-Use OpenSSL ​to compute the MD5 and SHA-1 hashes of the newly downloaded file; print the output in hexadecimal. +
- +
-To check your results, you can use ''​md5sum''​ or ''​sha1sum''​ as an alternative way of computing ​the same hashes. +
- +
-==== Exercise 3 ==== +
- +
-In this second exercise we'll use the command line to compute an HMAC, with SHA-1 as the hashing algorithm. +
- +
-Recall from the lecture that for HMAC to be secure, we need to sample a random key $k \gets \mathcal{K}$. +
- +
-We can generate random bytes using ''​openssl rand''​. To compute HMACs, check the documentation for ''​openssl dgst''​. +
- +
-For this exercise, use OpenSSL commands to: +
-  - generate a 16 byte random key +
-  - use the key to compute the SHA-1 HMAC of the page downloaded in the previous exercise +
- +
- +
-==== Exercise 4 ==== +
- +
-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. +
- +
-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}}. +
- +
-To compute a digest, you might find the code below useful: +
- +
-<code C> +
-    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>​ +
-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. +
- +
-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 install_sw +
-</​code>​ +
- +
-To fix the makefile using the new paths, change the variables at the start with the ones below: +
-<code makefile>​ +
-LDFLAGS=-L/​home/​student/​local/​lib -lcrypto +
-CFLAGS=-Wall -g -I/​home/​student/​local/​include +
-</​code>​ +
-</​note>​+
ac/laboratoare/04.1506362169.txt.gz · Last modified: 2017/09/25 20:56 by dan.dragan
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0