def test_fake_ciphertext_decryption_oracle(amount=5): for _ in range(amount): new_plaintext = random_bytes(randint(1, 10)) new_plaintext_padded = add_padding(new_plaintext, block_size) print("Test small: cbc.fake_ciphertext(new_plaintext_padded, decryption_oracle=decryption_oracle)") new_ciphertext = cbc.fake_ciphertext(new_plaintext_padded, decryption_oracle=decryption_oracle) decrypted = h2b(subprocess.check_output( ['python', cbc_oracles_path, 'decrypt', b2h(new_ciphertext)]).strip().decode()) assert decrypted == new_plaintext for _ in range(amount): new_plaintext = random_bytes(randint(10, 50)) new_plaintext_padded = add_padding(new_plaintext, block_size) print("Test large: cbc.fake_ciphertext(new_plaintext_padded, decryption_oracle=decryption_oracle)") new_ciphertext = cbc.fake_ciphertext(new_plaintext_padded, decryption_oracle=decryption_oracle, padding_oracle=padding_oracle) decrypted = h2b(subprocess.check_output( ['python', cbc_oracles_path, 'decrypt', b2h(new_ciphertext)]).strip().decode()) assert decrypted == new_plaintext
def test_bit_flipping(): print("Test: cbc.bit_flipping(ciphertext=ciphertext[-2*AES.block_size:]," "plaintext=add_padding(plaintext)[-AES.block_size:],\nwanted_last_block=wanted, block_size=AES.block_size)") plaintext = bytes(b"money=10000&userdata=whateverdata%20huehuehue%20spam%20and%20eggs") wanted = add_padding(bytes(b'&admin=true')) ciphertext = h2b(subprocess.check_output(['python', cbc_oracles_path, 'encrypt', b2h(plaintext)]).strip().decode()) fake_cipher = cbc.bit_flipping(ciphertext=ciphertext[-2*AES.block_size:], plaintext=add_padding(plaintext)[-AES.block_size:], wanted=wanted, block_size=AES.block_size) fake_cipher = ciphertext[-AES.block_size*2:] + fake_cipher decrypted = h2b(subprocess.check_output(['python', cbc_oracles_path, 'decrypt', b2h(fake_cipher)]).strip().decode()) assert decrypted[-len("&admin=true"):] == bytes(b"&admin=true")
def encryption_oracle_des(payload): global constant, prefix_len, suffix_len, secret if secret: if constant: payload = random_bytes(prefix_len) + payload + secret else: payload = random_bytes(random.randint(1, 50)) + payload + secret else: if constant: payload = random_bytes(prefix_len) + payload + random_bytes( suffix_len) else: payload = random_bytes(random.randint( 1, 50)) + payload + random_bytes(random.randint(1, 50)) payload = add_padding(payload, DES3.block_size) cipher = DES3.new(key_DES3, DES3.MODE_ECB) return cipher.encrypt(payload)
def test_iv_as_key(from_test=1): global iv_as_key iv_as_key = True plaintext = random_bytes(randint(1, 40)) plaintext_padded = add_padding(plaintext, block_size) ciphertext = encrypt(plaintext, iv_as_key=iv_as_key) if from_test <= 1: print("Test 1: cbc.iv_as_key()") key = cbc.iv_as_key(ciphertext[AES.block_size:], plaintext_padded, padding_oracle=padding_oracle) assert key == KEY if from_test <= 2: print("Test 2: cbc.iv_as_key()") key = cbc.iv_as_key(ciphertext[AES.block_size:], plaintext_padded, decryption_oracle=decryption_oracle) assert key == KEY iv_as_key = False
def decrypt(encryption_oracle, constant=True, block_size=16, prefix_size=None, secret_size=None, alphabet=None): """Given encryption oracle which produce ecb(prefix || our_input || secret), find secret Args: encryption_oracle(callable) constant(bool): True if prefix have constant length (secret must have constant length) block_size(int/None) prefix_size(int/None) secret_size(int/None) alphabet(string): plaintext space Returns: secret(string) """ log.debug("Start decrypt function") if not alphabet: alphabet = bytes(string.printable.encode()) if not block_size: block_size = find_block_size(encryption_oracle, constant) if constant: log.debug("constant == True") if not prefix_size or not secret_size: prefix_size, secret_size = find_prefix_suffix_size(encryption_oracle, block_size) """Start decrypt""" secret = bytes(b'') aligned_bytes = random_bytes(1) * (block_size - (prefix_size % block_size)) if len(aligned_bytes) == block_size: aligned_bytes = bytes(b'') aligned_bytes_suffix = random_bytes(1) * (block_size - (secret_size % block_size)) if len(aligned_bytes_suffix) == block_size: aligned_bytes_suffix = bytes(b'') block_to_find_position = -1 controlled_block_position = (prefix_size+len(aligned_bytes)) // block_size while len(secret) < secret_size: if (len(secret)+1) % block_size == 0: block_to_find_position -= 1 payload = aligned_bytes + aligned_bytes_suffix + random_bytes(1) + secret enc_chunks = chunks(encryption_oracle(payload), block_size) block_to_find = enc_chunks[block_to_find_position] log.debug("To guess at position {}:".format(block_to_find_position)) log.debug("Plain: " + print_chunks(chunks(bytes(b'P'*prefix_size) + payload + bytes(b'S'*secret_size), block_size))) log.debug("Encry: " + print_chunks(enc_chunks)+"\n") for guessed_char in range(256): guessed_char = bytes([guessed_char]) payload = aligned_bytes + add_padding(guessed_char + secret, block_size) enc_chunks = chunks(encryption_oracle(payload), block_size) log.debug("Plain: " + print_chunks(chunks(bytes(b'P'*prefix_size) + payload + bytes(b'S'*secret_size), block_size))) log.debug("Encry: " + print_chunks(enc_chunks)+"\n") if block_to_find == enc_chunks[controlled_block_position]: secret = guessed_char + secret log.debug("Found char, secret={}".format(repr(secret))) break else: log.critical_error("Char not found, try change alphabet. Secret so far: {}".format(repr(secret))) log.success("Secret(hex): {}".format(b2h(secret))) return secret else: log.debug("constant == False")
def encrypt(data, iv_as_key=False): iv = random_bytes(block_size) if iv_as_key: iv = KEY aes = AES.new(KEY, AES.MODE_CBC, iv) return iv + bytes(aes.encrypt(add_padding(data)))
def test_decrypt(from_test=1): original_plaintext = random_bytes(randint(1, 40)) original_ciphertext = encrypt(original_plaintext) original_plaintext = add_padding(original_plaintext, block_size) if from_test <= 1: print("Test 1: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True)") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True) assert decrypted == original_plaintext if from_test <= 2: data = original_ciphertext[:-block_size - 1] + bytes(b'A') + original_ciphertext[-block_size:] print("Test 2: cbc.decrypt(data, padding_oracle=padding_oracle, is_correct=False)") decrypted = cbc.decrypt(data, padding_oracle=padding_oracle, is_correct=False) assert decrypted[-block_size:-1] == original_plaintext[-block_size:-1] if from_test <= 3: print("Test 3: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=False)") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=False) assert decrypted[:-1] == original_plaintext[:-1] if from_test <= 4: iv = original_ciphertext[:block_size] data = original_ciphertext[block_size:] print("Test 4: cbc.decrypt(data, padding_oracle=padding_oracle, iv=iv)") decrypted = cbc.decrypt(data, padding_oracle=padding_oracle, iv=iv) assert decrypted == original_plaintext if from_test <= 5: if len(original_plaintext) > block_size: print("Test 5: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, amount=2)") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, amount=2) assert decrypted == original_plaintext[-block_size * 2:] if from_test <= 6: print("Test 6: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, amount=1, is_correct=True)") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, amount=1, is_correct=True) assert decrypted == original_plaintext[-block_size:] if from_test <= 7: print("Test 7: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, \n \ known_plaintext=original_plaintext)") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, known_plaintext=original_plaintext) assert decrypted == original_plaintext if from_test <= 8: print("Test 8: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, \n \ known_plaintext=original_plaintext[-4:])") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, known_plaintext=original_plaintext[-4:]) assert decrypted == original_plaintext if from_test <= 9: print("Test 9: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, \n \ known_plaintext=original_plaintext[-7:], amount=1)") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, known_plaintext=original_plaintext[-7:], amount=1) assert decrypted == original_plaintext[-block_size:] if from_test <= 10: print("Test 10: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=False, \n \ known_plaintext=original_plaintext[-7:], amount=1)") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=False, known_plaintext=original_plaintext[-7:], amount=1) assert decrypted == original_plaintext[-block_size:] if from_test <= 11: print("Test 11: cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, \n \ known_plaintext=original_plaintext[-block_size - 3:])") decrypted = cbc.decrypt(original_ciphertext, padding_oracle=padding_oracle, is_correct=True, known_plaintext=original_plaintext[-block_size - 3:]) assert decrypted == original_plaintext if from_test <= 12: print("Test 12: cbc.decrypt(original_ciphertext, decryption_oracle=decryption_oracle, is_correct=True, \n \ known_plaintext=original_plaintext[-block_size - 3:])") decrypted = cbc.decrypt(original_ciphertext, decryption_oracle=decryption_oracle, known_plaintext=original_plaintext[-block_size - 3:], is_correct=True) assert decrypted == original_plaintext if from_test <= 13: print("Test 13: cbc.decrypt(original_ciphertext, decryption_oracle=decryption_oracle)") decrypted = cbc.decrypt(original_ciphertext, decryption_oracle=decryption_oracle) assert decrypted == original_plaintext