def chal4(): """ One of the 60-character strings in input/4.txt has been encrypted with single-character XOR. Find it and decrypt it. """ f = open('input/4.txt') # TODO Fenimore's suggestion about using an uppercase key OUT = b'nOW\x00THAT\x00THE\x00PARTY\x00IS\x00JUMPING*' best_score = 0 result = '' for line in f: ciphertext = utils.hex_to_bytes(line.strip()) # Assume the most popular byte in the ciphertext is the key key = utils.get_popular_byte(ciphertext) # Try the key plaintext_bytes = _crypto.xor_single_byte_key(ciphertext, key) score = utils.english_score(str(plaintext_bytes)) # The decrypted string that looks most like English is most # likely the one we're looking for if score > best_score: best_score = score result = plaintext_bytes expect(result.decode('utf-8'), OUT.decode('utf-8'))
def chal6(): """ The text in input/6.txt has been base64 encoded after being encrypted with repeating-key XOR. Decrypt it. """ f = open('input/6.txt') ciphertext = utils.base64_to_bytes(f.read()) best_english_score = 0 result = '' keysizes = utils.find_possible_keysizes(ciphertext, 3, 2, 40) for keysize in keysizes: key = [0] * keysize # Split the ciphertext into blocks of length keysize blocks = [ciphertext[i:i+keysize] for i in range(0, len(ciphertext), keysize)] # Transpose the blocks transposed = [bytes(t) for t in zip_longest(*blocks, fillvalue=0)] # Treat each block as if it's been encrypted with a # repeating-key XOR for i in range(0, len(transposed)-1): key[i] = utils.get_popular_byte(transposed[i]) plaintext = _crypto.xor_repeating_key(ciphertext, bytes(key)) english_score = utils.english_score(plaintext.decode('utf-8')) if english_score > best_english_score: result = plaintext.decode('utf-8')