except IndexError: # Don't try keys that are too long break edit_dist_1 = float(util.edit_dist(first_bytes, second_bytes)) / key_len edit_dist_2 = float(util.edit_dist(second_bytes, third_bytes)) / key_len edit_dist_3 = float(util.edit_dist(third_bytes, fourth_bytes)) / key_len avg = (edit_dist_1 + edit_dist_2 + edit_dist_3) / 3 lens_and_distances.append((key_len, avg)) best_keysizes = sorted(lens_and_distances, key=lambda tup: tup[1])[0: N_KEYSIZES] print(best_keysizes) for (keysize, score) in best_keysizes: # Break the ciphertext into blocks of size KEYSIZE, and transpose the # blocks so that the first char of the first block goes with first char # of second block, second chars go together, etc. transposed_blocks = break_and_transpose(ctext, keysize) full_key = '' # Next, solve each block as though it was single-character XOR to find # that part of the key. Put the best guesses for the single-character # keys together and use these to guess the actual key. for block in transposed_blocks: (_, _, key) = util.solve_single_char_xor(block) full_key += key # Correct plaintext isn't top result for the example (6.txt), but it's # in the output. :D print('Key: ' + full_key) print(util.xor_repeating(ctext, full_key))
"""Repeating key XOR. Function is implemented in util, an example of usage is here.""" from util import xor_repeating PLAINTEXT = ("Burning 'em, if you ain't quick and nimble\n" "I go crazy when I hear a cymbal") KEY = 'ICE' if __name__ == '__main__': print(xor_repeating(PLAINTEXT, KEY).encode('hex'))