Question: Could you help me with the decryption? # ! / usr / bin / python 3 # Run me like this: # $ python 3

Could you help me with the decryption?
#!/usr/bin/python3
# Run me like this:
# $ python3 padding_oracle.py "WEBSITE" "5a7793d3..."
# or select "Padding Oracle" from the VS Code debugger
import json
import sys
import time
from typing import Union, Dict, List
import requests
# Create one session for each oracle request to share. This allows the
# underlying connection to be re-used, which speeds up subsequent requests!
s = requests.session()
def oracle(url: str, messages: List[bytes])-> List[Dict[str, str]]:
while True:
try:
r = s.post(url, data={"message": [m.hex() for m in messages]})
r.raise_for_status()
return r.json()
# Under heavy server load, your request might time out. If this happens,
# the function will automatically retry in 10 seconds for you.
except requests.exceptions.RequestException as e:
sys.stderr.write(str(e))
sys.stderr.write("
Retrying in 10 seconds...
")
time.sleep(10)
continue
except json.JSONDecodeError as e:
sys.stderr.write("It's possible that the oracle server is overloaded right now, or that provided URL is wrong.
")
sys.stderr.write("If this keeps happening, check the URL. Perhaps your uniqname is not set.
")
sys.stderr.write("Retrying in 10 seconds...
")
time.sleep(10)
continue
def main():
if len(sys.argv)!=3:
print(f"usage: {sys.argv[0]} ORACLE_URL CIPHERTEXT_HEX", file=sys.stderr)
sys.exit(-1)
oracle_url, message = sys.argv[1], bytes.fromhex(sys.argv[2])
if oracle(oracle_url, [message])[0]["status"]!= "valid":
print("Message invalid", file=sys.stderr)
#
# TODO: Decrypt the message
#
decrypted = "TODO"
print(decrypted)
if __name__=='__main__':
main()
Here is some Python code representing what we suspect the server does when the /verify
endpoint is accessed:
from Crypto.Cipher import AES
from Crypto.Hash import HMAC, SHA256
from Crypto.Random import get_random_bytes
def pad(message):
n = AES.block_size - len(message)% AES.block_size
if n ==0: n = AES.block_size
return message + bytes([n]*n)
def unpad(message):
n = message[-1]
if n <1 or n > AES.block_size or message[-n:]!= bytes([n]*n):
raise Exception('invalid_padding')
return message[:-n]
def encrypt(message, key):
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(pad(message))
def decrypt(ciphertext, key):
if len(ciphertext)% AES.block_size: raise Exception('invalid_len')
if len(ciphertext)<2*AES.block_size: raise Exception('invalid_iv')
iv = ciphertext[:AES.block_size]
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(ciphertext[AES.block_size:]))
Page 3
def hmac(message, mac_key):
h = HMAC.new(mac_key, digestmod=SHA256)
h.update(message)
return h.digest()
def verify(message, mac, mac_key):
if mac != hmac(message, mac_key):
raise Exception('invalid_mac')
def macThenEncrypt(message, key, mac_key):
return encrypt(message + hmac(message, mac_key), key)
def decryptThenVerify(ciphertext, key, mac_key):
plaintext = decrypt(ciphertext, key)
message, mac = plaintext[:-SHA256.digest_size],
plaintext[-SHA256.digest_size:]
verify(message, mac, mac_key)
return message
@app.route('/verify', methods=['POST'])
def dec_oracle_route():
ciphertext = bytes.fromhex(request.form['message'])
try:
decryptThenVerify(ciphertext, KEY, MAC_KEY)
except(e):
return {'status': e}
return {'status': 'valid'}
Hint: The real verify endpoint is a bit more powerful. It can accept multiple message
arguments, in which case it returns the results as a JSON array, in the same order as the
arguments. See the oracle function in the starter code for more details.

Step by Step Solution

There are 3 Steps involved in it

1 Expert Approved Answer
Step: 1 Unlock blur-text-image
Question Has Been Solved by an Expert!

Get step-by-step solutions from verified subject matter experts

Step: 2 Unlock
Step: 3 Unlock

Students Have Also Explored These Related Programming Questions!