def get_unknown_bytes(oracle):
    min_ciphertext_length = len(oracle(""))
    prev = min_ciphertext_length
    block_size = -1
    for i in range(min_ciphertext_length):
        l = len(oracle("A"*i))
        if l != prev:
            block_size = l - prev
            break
    assert block_size != -1

    assert detect_ECB_text(oracle("A"*(8*block_size)), block_size)
    uid = randint(0, 128)
    plaintext = ""
    shim_block = "A"*(block_size - 1)
    block_count = min_ciphertext_length/block_size
    for i in range(block_count):
        next_shim = ""
        for j in range(block_size):
            oracle_text = oracle(shim_block)
            target_block = oracle_text[i*block_size:(i+1)*block_size]

            for k in range(256):
                guess = shim_block + next_shim + chr(k)
                result = oracle(guess)[0:block_size]
                if result == target_block:
                    shim_block = shim_block[1:]
                    next_shim += chr(k)
                    break
                    
        plaintext += next_shim
        shim_block = next_shim[1:]

    return plaintext[:-1]
def get_unknown_bytes_with_rand_prefix(nonfuzzed_oracle):
    # Generate our obfuscated oracle
    fuzzed_oracle = lambda s: nonfuzzed_oracle(urandom(randint(0, 512)) + s)

    block_size = 16

    # (For the sake of completeness) verify that the oracle is in ECB mode
    assert detect_ECB_text(fuzzed_oracle("A"*(8*block_size)), block_size)

    marker_block = "B"*(block_size - 1) + "C"
    marker_target = None
    while True:
        result = fuzzed_oracle(marker_block*8)
        blocks = split_into_blocks(result, block_size)
        for i in range(len(blocks) - 8):
            if len(set(blocks[i:i+8])) == 1:
                marker_target = blocks[i]
                break
        if marker_target != None:
            break

    assert marker_target != None
    assert len(marker_target) == block_size


    def defuzzed_oracle(s):
        # Find the marker target, and truncate it and everything before it.
        # This removes the random bytes prepended by the fuzzed oracle.
        while True:
            result = fuzzed_oracle(marker_block + s)
            if marker_target in result:
                target_index = result.index(marker_target)
                return result[target_index + block_size:]

        raise AssertionError("defuzzed_oracle went haywire and somehow returned None.")

    return get_unknown_bytes(defuzzed_oracle)