The web application located here attempts to decrypt the url-encoded string passed into it using 128-bit AES in CBC mode with a fixed key, remove the PKCS 7 and confirm whether the decrypted plaintext corresponds to the location of your next homework assignment. It will throw an error if it encounters any problems in this process.
Your task is to use the technique described in Vaudenay's 2002 paper to recover the plaintext from the above link in order to reach the rest of your homework.
Please write your program in Python 3. Your program should take in a URL as a command-line argument, carry out the padding oracle attack using the HTTP responses that our server does, and print out the decrypted ciphertext. Gradescope will expect the file to be named hw3-sol.py.
I highly recommend writing your own encryption/decryption oracle in order to debug your attack logic before attempting to launch the attack against our server.
Please submit your code and a short description of how you solved the problem along with a PDF named hw3-solutions.pdf of your LaTeXed solutions to the other problems to Gradescope before class on Wednesday, April 22. You may discuss this assignment in small groups with classmates, but please code and write up your solutions yourself. Please credit any collaborators you discussed with and any references you used.
For reference, here is some framework code that will print out the HTTP status and decoded query string for a URL supplied on the command line, along with the encryption, decryption, and padding functions the server uses.
#!/usr/bin/env python3
from Crypto.Cipher import AES
from Crypto import Random
import urllib.parse, urllib.request
import sys
def pad(msg,blocksize=16):
n = blocksize-(len(msg)%16)
return msg+bytes([n]*n)
def strip_padding(msg):
padlen = msg[-1]
if padlen > 16:
return None
if msg[-padlen:] != bytes([padlen]*padlen):
return None
return msg[:-padlen]
def enc(key,msg):
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(pad(msg))
def dec(key,msg):
cipher = AES.new(key, AES.MODE_CBC, msg[:16])
text = strip_padding(cipher.decrypt(msg[16:]))
return text
def get_status(u):
req = urllib.request.Request(u)
try:
with urllib.request.urlopen(req) as f:
print("HTTP Response:", f.code)
except urllib.error.HTTPError as e:
print("HTTP Respone:", e.code)
except urllib.error.URLError as e:
print("URL Error:", e.code)
if __name__=='__main__':
parsed_url = urllib.parse.urlsplit(sys.argv[1])
query_string = urllib.request.unquote_to_bytes(parsed_url.query)
print("Query string:", query_string)
get_status(urllib.parse.urlunsplit(parsed_url))
exit(0)