def forge_via_length_extension(attacker_id: str, victim_id: str) -> bytes: victim = ClientV2(victim_id) server = ServerV2() # Intercept transaction from victim to some recipient "8". payload = victim.send({"8": 100}) assert server.validate(payload) message, t = parse_payload_v2(payload) message = pkcs7(message) # It's important to keep track of the padding. # CBC-MAC extension works because for some t = mac(m_1), # mac(m1 || m_2) = mac(t xor m_2). # We want to concatonate the original message with our own extension, # which will be a transaction to our ID for 1,000,000 spacebucks. # Conveniently that's the largest order of magnitude amount that we # can squeeze into the extension. # We need to keep the "from=..." field intact. It's 6 bytes long. The # below xor ensures that in the extension attack, the resulting message # will retain the original 6 bytes. mandatory_xor = fixed_xor(message[:6], t[:6]) extension = mandatory_xor + b";" + attacker_id.encode() + b":1000000" # Extend and generate a new CBC-MAC. # Yeah, we call victim.cbc_mac here. m_prime = message + extension mac_prime = victim.cbc_mac(fixed_xor(t, extension)) payload = m_prime + mac_prime assert server.validate(payload) return payload
def oracle(userdata: bytes) -> bytes: key = RANDOM_KEY prefix = b"comment1=cooking%20MCs;userdata=" postfix = b";comment2=%20like%20a%20pound%20of%20bacon" userdata = userdata.replace(b";", b"").replace(b"=", b"") plaintext = pkcs7(prefix + userdata + postfix) return encrypt_aes_cbc(key, iv=bytes(16), plaintext=plaintext)
def oracle(plaintext: bytes) -> bytes: prefix = RANDOM_PREFIX with open("data/12.txt") as data_fd: unknown_string = b64decode(data_fd.read()) plaintext = pkcs7(prefix + plaintext + unknown_string, 16) cypher = AES.new(RANDOM_KEY, AES.MODE_ECB) return cypher.encrypt(plaintext)
def rewrite_cookie(email = "*****@*****.**"): bs = 16 assert len(email) % bs == 13, "email must be 13 (mod 16) characters" admin_block = pkcs7(b'admin', bs).decode() d = int(len(email) / bs) * bs email = email[:-3] + admin_block + email[-3:] c = oracle(email) return c[:bs+d] + c[2*bs+d:3*bs+d] + c[bs+d:2*bs+d]
def rewrite_cookie(email: str) -> bytes: bs = 16 if len(email) % bs != 13: raise ValueError(f"email must be 13 (mod {bs}) characters") admin_block = pkcs7(b"admin", bs).decode() d = int(len(email) / bs) * bs email = email[:-3] + admin_block + email[-3:] c = oracle(email) return c[:bs + d] + c[2 * bs + d:3 * bs + d] + c[bs + d:2 * bs + d]
def forge_hash(m: bytes, m_prime: bytes, key: bytes, iv: bytes) -> bytes: t = cbc_mac(key, iv, pkcs7(m)) t_prime = cbc_mac(key, iv, m_prime) # We need to find m'' such that E_k(m'' xor t') = t # by solving D_k(t) xor t' = m''. m_prime_suffix = decrypt_aes_cbc(key, t_prime, t) return m_prime + m_prime_suffix
def main() -> None: m = b"alert('MZA who was that?');\n" key = b"YELLOW SUBMARINE" iv = bytes(16) # No padding because it aligns with the blocksize. m_prime = b"alert('Ayo, the Wu is back!');//" forgery = forge_hash(m, m_prime, key, iv) assert cbc_mac(key, iv, pkcs7(m)) == cbc_mac(key, iv, forgery) print(forgery)
def encryption_oracle(plaintext: bytes) -> bytes: plaintext = bytes(randrange(5, 11)) + plaintext + bytes(randrange(5, 11)) plaintext = pkcs7(plaintext) key = get_random_bytes(16) if randrange(2) == 0: iv = get_random_bytes(16) return encrypt_aes_cbc(key, iv, plaintext) cypher = AES.new(key, AES.MODE_ECB) return cypher.encrypt(plaintext)
def encryption_oracle(plaintext): plaintext = bytes(randrange(5, 11)) + plaintext + bytes(randrange(5, 11)) plaintext = pkcs7(plaintext, 16) key = bytes(getrandbits(8) for i in range(16)) if randrange(0,2) == 0: iv = bytes(getrandbits(8) for i in range(16)) cyphertext = encrypt_aes_cbc(plaintext, key, iv) #print("CBC") else: cypher = AES.new(key, AES.MODE_ECB) cyphertext = cypher.encrypt(plaintext) #print("ECB") return cyphertext
def oracle(plaintext: bytes) -> bytes: with open("data/12.txt", "r") as data_handle: unknown_string = b64decode(data_handle.read()) plaintext = pkcs7(plaintext + unknown_string, 16) cypher = AES.new(RANDOM_KEY, AES.MODE_ECB) return cypher.encrypt(plaintext)
def send(self, to_id: str, amount: int) -> bytes: message = self.compose_message(self.id, to_id, amount) iv = get_random_bytes(BLOCKSIZE) return message + iv + cbc_mac(KEY, iv, pkcs7(message))
def send_message(self, message: bytes) -> None: iv = get_random_bytes(16) cyphertext = encrypt_aes_cbc(self._aes_key(), iv, pkcs7(message)) self.peer.receive_message(cyphertext + iv)
def oracle(userdata, k = RANDOM_KEY): prefix = b'comment1=cooking%20MCs;userdata=' postfix = b';comment2=%20like%20a%20pound%20of%20bacon' userdata = userdata.replace(";", "").replace("=", "") plaintext = pkcs7(prefix + bytes(userdata, "ascii") + postfix) return encrypt_aes_cbc(plaintext, k, iv = bytes(16))
def validate(payload: bytes) -> bool: message, iv, mac = parse_payload_v1(payload) return compare_digest(cbc_mac(KEY, iv, pkcs7(message)), mac)
def oracle(userdata: bytes) -> bytes: prefix = b"comment1=cooking%20MCs;userdata=" postfix = b";comment2=%20like%20a%20pound%20of%20bacon" userdata = userdata.replace(b";", b"").replace(b"=", b"") plaintext = pkcs7(prefix + userdata + postfix) return aes_ctr(plaintext, RANDOM_KEY)
def send(self, tx_list: dict[str, int]) -> bytes: """Return a payload for the server""" message = self._compose(tx_list) return message + self.cbc_mac(pkcs7(message))
def oracle(email: str) -> bytes: profile = profile_for(email) cypher = AES.new(RANDOM_KEY, AES.MODE_ECB) return cypher.encrypt(pkcs7(bytes(profile, "ascii"), 16))
def oracle(plaintext = b''): unknown_string = b64decode(open("data/12.txt", "r").read()) plaintext = pkcs7(plaintext + unknown_string, 16) cypher = AES.new(RANDOM_KEY, AES.MODE_ECB) return cypher.encrypt(plaintext)
def bad_cbc_encryption(plaintext: bytes) -> bytes: key = RANDOM_KEY return encrypt_aes_cbc(key, iv=key, plaintext=pkcs7(plaintext))
def cbc_oracle(plaintext: bytes) -> int: """CBC-mode compression orcle""" key = get_random_bytes(BLOCKSIZE) iv = get_random_bytes(BLOCKSIZE) return len( encrypt_aes_cbc(key, iv, pkcs7(compress(format_request(plaintext)))))
def validate(payload: bytes) -> bool: """Unreasonably flexible payload validation""" message, mac = parse_payload_v2(payload) if len(message) % 16 != 0: message = pkcs7(message) return compare_digest(cbc_mac(KEY, bytes(16), message), mac)
def oracle(email): profile = profile_for(email) cypher = AES.new(RANDOM_KEY, AES.MODE_ECB) return cypher.encrypt(pkcs7(bytes(profile, "ascii"), 16))
def chose_plaintext(): f = open("data/17.txt", "r").read().splitlines() return pkcs7(b64decode(f[randint(0, len(f) - 1)]))
def pkcs7(plaintext: bytes, blocksize: int = 16) -> bytes: return m09.pkcs7(plaintext, blocksize)