def find_prefix_len(oracle, blocksize): input_len = 2 * blocksize # increase input until we generate 2 identical blocks while True: # test with 2 different blocks to make sure that we're not using the # last bytes from the prefix input1 = bytes([0] * input_len) input2 = bytes([1] * input_len) blocks1 = get_blocks(oracle(input1), blocksize) blocks2 = get_blocks(oracle(input2), blocksize) if has_duplicates(blocks1) and has_duplicates(blocks2): break input_len += 1 # find the index where the first of these 2 identical blocks is blocks = get_blocks(oracle(bytes([0] * input_len)), blocksize) first_idx = [i * blocksize for i in range(len(blocks)-1) if blocks[i] == blocks[i+1]][0] padding = input_len - 2 * blocksize return first_idx - padding
def find_prefix_len(oracle, blocksize): input_len = 2 * blocksize # increase input until we generate 2 identical blocks while True: # test with 2 different blocks to make sure that we're not using the # last bytes from the prefix input1 = bytes([0] * input_len) input2 = bytes([1] * input_len) blocks1 = get_blocks(oracle(input1), blocksize) blocks2 = get_blocks(oracle(input2), blocksize) if has_duplicates(blocks1) and has_duplicates(blocks2): break input_len += 1 # find the index where the first of these 2 identical blocks is blocks = get_blocks(oracle(bytes([0] * input_len)), blocksize) first_idx = [ i * blocksize for i in range(len(blocks) - 1) if blocks[i] == blocks[i + 1] ][0] padding = input_len - 2 * blocksize return first_idx - padding
def main(): SECRETS = [ "MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=", "MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic=", "MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw==", "MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==", "MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl", "MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==", "MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==", "MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=", "MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=", "MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93" ] for secret in SECRETS: iv, encrypted = get_secret(secret) blocks = [bytes(iv)] + get_blocks(encrypted) decrypted_blocks = [ decrypt_block(padding_oracle, blocks[i - 1], blocks[i]) for i in range(1, len(blocks)) ] padded_plaintext = b"".join(decrypted_blocks) plaintext = unpad(padded_plaintext) print(plaintext.decode('ascii')) assert (b64encode(plaintext).decode('ascii') == secret)
def guess_blockmode(oracle): input_ = bytes([0x42] * 100) encrypted, answer = oracle(input_) blocks = get_blocks(encrypted) unique_blocks = len(set(blocks)) guess = "ECB" if unique_blocks != len(blocks) else "CBC" assert (guess == answer)
def guess_blockmode(oracle): input_ = bytes([0x42] * 100) encrypted, answer = oracle(input_) blocks = get_blocks(encrypted) unique_blocks = len(set(blocks)) guess = "ECB" if unique_blocks != len(blocks) else "CBC" assert(guess == answer)
def is_ecb(oracle, blocksize): encrypted = oracle(bytes([0x42] * 3 * blocksize)) blocks = get_blocks(encrypted, blocksize) return has_duplicates(blocks)
prefix_padding_len = (blocksize - prefix_len % blocksize) % blocksize prefix_padding = bytes([0] * prefix_padding_len) prefix_blocks_len = (prefix_len + prefix_padding_len) // blocksize assert(PREFIX_LEN == prefix_len) plaintext = bytearray() while True: # can't tell when we're done beforehand, prefix is random for byte_idx in range(blocksize): last_known_block = get_last_known_block(plaintext, blocksize) input_, target_block_idx = target_next_byte(plaintext, blocksize) target_block_idx += prefix_blocks_len encrypted = oracle(prefix_padding + input_) target_block = get_blocks(encrypted, blocksize)[target_block_idx] block_prefix = last_known_block[1:] found_match = False for byte in range(256): ciphertext_guess = block_prefix + bytes([byte]) encrypted_guess = oracle(prefix_padding + ciphertext_guess) guess = get_blocks(encrypted_guess, blocksize)[prefix_blocks_len] if target_block == guess: found_match = True plaintext.append(byte) stdout.write(chr(byte)) stdout.flush() break
""" verified_byte = None for byte in valid_bytes: original_prev_block = bytes([0] * 14 + [0, byte]) tampered_prev_block = bytes([0] * 14 + [1, byte]) if (oracle(original_prev_block, current_block) and oracle(tampered_prev_block, current_block)): assert(verified_byte is None) verified_byte = byte return verified_byte def get_expected_padding_byte(known_pre_xor): return len(known_pre_xor) + 1 for secret in SECRETS: iv, encrypted = get_secret(secret) blocks = [bytes(iv)] + get_blocks(encrypted) decrypted_blocks = [decrypt_block(padding_oracle, blocks[i-1], blocks[i]) for i in range(1, len(blocks))] padded_plaintext = b"".join(decrypted_blocks) plaintext = unpad(padded_plaintext) print(plaintext.decode('ascii')) assert(b64encode(plaintext).decode('ascii') == secret)
for byte in valid_bytes: original_prev_block = bytes([0] * 14 + [0, byte]) tampered_prev_block = bytes([0] * 14 + [1, byte]) if (oracle(original_prev_block, current_block) and oracle(tampered_prev_block, current_block)): assert (verified_byte is None) verified_byte = byte return verified_byte def get_expected_padding_byte(known_pre_xor): return len(known_pre_xor) + 1 for secret in SECRETS: iv, encrypted = get_secret(secret) blocks = [bytes(iv)] + get_blocks(encrypted) decrypted_blocks = [ decrypt_block(padding_oracle, blocks[i - 1], blocks[i]) for i in range(1, len(blocks)) ] padded_plaintext = b"".join(decrypted_blocks) plaintext = unpad(padded_plaintext) print(plaintext.decode('ascii')) assert (b64encode(plaintext).decode('ascii') == secret)
from aes import get_blocks with open('08.txt') as f: ciphertexts = [bytes.fromhex(line.strip()) for line in f.readlines()] ciphertexts_blocks = [get_blocks(ciphertext) for ciphertext in ciphertexts] uniques = [len(set(block)) for block in ciphertexts_blocks] least_unique_idx = uniques.index(min(uniques)) ecb_encrypted = ciphertexts[least_unique_idx] print("ECB: %s" % ecb_encrypted) print("%i unique blocks out of %i" % (uniques[least_unique_idx], len(ciphertexts[least_unique_idx])/16)) assert(ecb_encrypted.startswith( b'\xd8\x80a\x97@\xa8\xa1\x9bx@\xa8\xa3\x1c\x81\n=\x08d\x9a\xf7'))
from aes import get_blocks with open('08.txt') as f: ciphertexts = [bytes.fromhex(line.strip()) for line in f.readlines()] ciphertexts_blocks = [get_blocks(ciphertext) for ciphertext in ciphertexts] uniques = [len(set(block)) for block in ciphertexts_blocks] least_unique_idx = uniques.index(min(uniques)) ecb_encrypted = ciphertexts[least_unique_idx] print("ECB: %s" % ecb_encrypted) print("%i unique blocks out of %i" % (uniques[least_unique_idx], len(ciphertexts[least_unique_idx]) / 16)) assert (ecb_encrypted.startswith( b'\xd8\x80a\x97@\xa8\xa1\x9bx@\xa8\xa3\x1c\x81\n=\x08d\x9a\xf7'))
def is_ecb(oracle, blocksize): encrypted = oracle(bytes([0x42] * 3 * blocksize)) blocks = get_blocks(encrypted, blocksize) unique_blocks = len(set(blocks)) return unique_blocks != len(blocks)
blocksize = guess_blocksize(oracle) assert(16 == blocksize) assert(is_ecb(oracle, blocksize)) bytes_count = len(oracle(bytes())) plaintext = bytearray() for _ in range(bytes_count): last_known_block = get_last_known_block(plaintext, blocksize) input_, target_block_idx = target_next_byte(plaintext, blocksize) encrypted = oracle(input_) target_block = get_blocks(encrypted)[target_block_idx] prefix = last_known_block[1:] found_match = False for byte in range(256): encrypted_guess = oracle(prefix + bytes([byte])) guess = get_blocks(encrypted_guess)[0] if target_block == guess: found_match = True plaintext.append(byte) stdout.write(chr(byte)) stdout.flush() break
prefix_padding_len = (blocksize - prefix_len % blocksize) % blocksize prefix_padding = bytes([0] * prefix_padding_len) prefix_blocks_len = (prefix_len + prefix_padding_len) // blocksize assert (PREFIX_LEN == prefix_len) plaintext = bytearray() while True: # can't tell when we're done beforehand, prefix is random for byte_idx in range(blocksize): last_known_block = get_last_known_block(plaintext, blocksize) input_, target_block_idx = target_next_byte(plaintext, blocksize) target_block_idx += prefix_blocks_len encrypted = oracle(prefix_padding + input_) target_block = get_blocks(encrypted, blocksize)[target_block_idx] block_prefix = last_known_block[1:] found_match = False for byte in range(256): ciphertext_guess = block_prefix + bytes([byte]) encrypted_guess = oracle(prefix_padding + ciphertext_guess) guess = get_blocks(encrypted_guess, blocksize)[prefix_blocks_len] if target_block == guess: found_match = True plaintext.append(byte) stdout.write(chr(byte)) stdout.flush() break