def test_decrypt(self): cipher = Transposition() open_text = normalize_text("Python is a general-purpose, interpreted high-level programming language") key = "password" cipher_text = cipher.encrypt(open_text, key) decrypted_text = cipher.decrypt(cipher_text, key) expected = open_text + "xx" self.assertEqual(decrypted_text, expected)
class LongWordAttack(object): """Cryptanalysis method for transposition cipher""" def __init__(self): super(LongWordAttack, self).__init__() self.max_keylen = 15 self.transposition = Transposition() def crack(self, cipher_text, langstats): key_text_pair = lambda key: ( key, self.transposition.decrypt(cipher_text, key)) key_text = (key_text_pair(key) for key in self._get_possible_keys(cipher_text, langstats)) return langstats.most_meaningful(key_text) def _get_possible_keys(self, cipher_text, langstats): reshuffle_text = self.transposition._partition_text_decrypt for keylen in self._key_lengths(cipher_text): all_words = langstats.get_words(keylen) for cipher_word in reshuffle_text(cipher_text, len(cipher_text) / keylen): cipher_counter = Counter(cipher_word) for real_word in all_words: if Counter(real_word) == cipher_counter: for key in self._get_valid_keys( cipher_word, real_word): yield key def _get_valid_keys(self, cipher_word, real_word): for perm in self._get_perms(cipher_word, 0, [], self.get_positions(real_word)): yield "".join(chr(x + ord('a')) for x in perm) def _get_perms(self, word, currPos, visited, positions): if currPos == len(word): yield visited else: c = word[currPos] for free in positions[c] - set(visited): for vis in self._get_perms(word, currPos + 1, visited + [free], positions): yield vis def get_positions(self, word): pos = {} for i, char in enumerate(word): if char in pos: pos[char].add(i) else: pos[char] = {i} return pos def _key_lengths(self, cipher_text): ltext = len(cipher_text) return (i for i in range(2, self.max_keylen + 1) if ltext % i == 0)
class LongWordAttack(object): """Cryptanalysis method for transposition cipher""" def __init__(self): super(LongWordAttack, self).__init__() self.max_keylen = 15 self.transposition = Transposition() def crack(self, cipher_text, langstats): key_text_pair = lambda key: (key, self.transposition.decrypt(cipher_text, key)) key_text = (key_text_pair(key) for key in self._get_possible_keys(cipher_text, langstats)) return langstats.most_meaningful(key_text) def _get_possible_keys(self, cipher_text, langstats): reshuffle_text = self.transposition._partition_text_decrypt for keylen in self._key_lengths(cipher_text): all_words = langstats.get_words(keylen) for cipher_word in reshuffle_text(cipher_text, len(cipher_text) / keylen): cipher_counter = Counter(cipher_word) for real_word in all_words: if Counter(real_word) == cipher_counter: for key in self._get_valid_keys(cipher_word, real_word): yield key def _get_valid_keys(self, cipher_word, real_word): for perm in self._get_perms(cipher_word, 0, [], self.get_positions(real_word)): yield "".join(chr(x + ord('a')) for x in perm) def _get_perms(self, word, currPos, visited, positions): if currPos == len(word): yield visited else: c = word[currPos] for free in positions[c] - set(visited): for vis in self._get_perms(word, currPos + 1, visited + [free], positions): yield vis def get_positions(self, word): pos = {} for i, char in enumerate(word): if char in pos: pos[char].add(i) else: pos[char] = {i} return pos def _key_lengths(self, cipher_text): ltext = len(cipher_text) return (i for i in range(2, self.max_keylen + 1) if ltext % i == 0)