Fiddling with cracking dictionaries
[cipher-tools.git] / cipher.py
index 7feaedf90fd289b9fda1da60f0dea9565e1108d1..5f39a780dd608d4385eb9db9d41c0c7b8edb4df7 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -1,8 +1,8 @@
 import string
 import collections
 import logging
 import string
 import collections
 import logging
-from itertools import zip_longest, cycle
-
+from itertools import zip_longest, cycle, chain
+from language_models import *
 
 logger = logging.getLogger(__name__)
 logger.addHandler(logging.FileHandler('cipher.log'))
 
 logger = logging.getLogger(__name__)
 logger.addHandler(logging.FileHandler('cipher.log'))
@@ -11,32 +11,12 @@ logger.setLevel(logging.WARNING)
 #logger.setLevel(logging.DEBUG)
 
 
 #logger.setLevel(logging.DEBUG)
 
 
-modular_division_table = [[0]*26 for x in range(26)]
+modular_division_table = [[0]*26 for _ in range(26)]
 for a in range(26):
     for b in range(26):
         c = (a * b) % 26
         modular_division_table[b][c] = a
 
 for a in range(26):
     for b in range(26):
         c = (a * b) % 26
         modular_division_table[b][c] = a
 
-def letters(text):
-    """Remove all non-alphabetic characters from a text
-    >>> letters('The Quick')
-    'TheQuick'
-    >>> letters('The Quick BROWN fox jumped! over... the (9lazy) DOG')
-    'TheQuickBROWNfoxjumpedoverthelazyDOG'
-    """
-    return ''.join([c for c in text if c in string.ascii_letters])
-
-def sanitise(text):
-    """Remove all non-alphabetic characters and convert the text to lowercase
-    
-    >>> sanitise('The Quick')
-    'thequick'
-    >>> sanitise('The Quick BROWN fox jumped! over... the (9lazy) DOG')
-    'thequickbrownfoxjumpedoverthelazydog'
-    """
-    # sanitised = [c.lower() for c in text if c in string.ascii_letters]
-    # return ''.join(sanitised)
-    return letters(text).lower()
 
 def ngrams(text, n):
     """Returns all n-grams of a text
 
 def ngrams(text, n):
     """Returns all n-grams of a text
@@ -237,8 +217,9 @@ def affine_decipher_letter(letter, multiplier=1, adder=0, one_based=True):
             alphabet_start = ord('a')
         cipher_number = ord(letter) - alphabet_start
         if one_based: cipher_number += 1
             alphabet_start = ord('a')
         cipher_number = ord(letter) - alphabet_start
         if one_based: cipher_number += 1
-        plaintext_number = ( modular_division_table[multiplier]
-                                                   [(cipher_number - adder) % 26] )
+        plaintext_number = ( 
+            modular_division_table[multiplier]
+                                  [(cipher_number - adder) % 26] )
         if one_based: plaintext_number -= 1
         return chr(plaintext_number % 26 + alphabet_start) 
     else:
         if one_based: plaintext_number -= 1
         return chr(plaintext_number % 26 + alphabet_start) 
     else:
@@ -407,38 +388,55 @@ def transpositions_of(keyword):
         transpositions = tuple(key.index(l) for l in sorted(key))
         return transpositions
 
         transpositions = tuple(key.index(l) for l in sorted(key))
         return transpositions
 
+def pad(message_len, group_len, fillvalue):
+    padding_length = group_len - message_len % group_len
+    if padding_length == group_len: padding_length = 0
+    padding = ''
+    for i in range(padding_length):
+        if callable(fillvalue):
+            padding += fillvalue()
+        else:
+            padding += fillvalue
+    return padding
+
 def column_transposition_encipher(message, keyword, fillvalue=' ', 
 def column_transposition_encipher(message, keyword, fillvalue=' ', 
-      columnwise=False):
+      fillcolumnwise=False,
+      emptycolumnwise=False):
     """Enciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
     """Enciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
-
-    >>> column_transposition_encipher('hellothere', 'clever')
-    'hleolteher'
-    >>> column_transposition_encipher('hellothere', 'cleverly', fillvalue='!')
-    'hleolthre!e!'
-    >>> column_transposition_encipher('hellothere', 'clever', columnwise=True)
-    'htleehoelr'
     """
     """
+    # >>> column_transposition_encipher('hellothere', 'clever')
+    # 'hleolteher'
+    # >>> column_transposition_encipher('hellothere', 'cleverly', fillvalue='!')
+    # 'hleolthre!e!'
+    # >>> column_transposition_encipher('hellothere', 'clever', columnwise=True)
+    # 'htleehoelr'
+    # """
     transpositions = transpositions_of(keyword)
     transpositions = transpositions_of(keyword)
+    message += pad(len(message), len(transpositions), fillvalue)
+    if fillcolumnwise:
+        rows = every_nth(message, len(transpositions))
+    else:
+        rows = chunks(mesage, len(transpositions))
     columns = every_nth(message, len(transpositions), fillvalue=fillvalue)
     columns = every_nth(message, len(transpositions), fillvalue=fillvalue)
-    transposed_columns = transpose(columns, transpositions)
-    if columnwise:
-        return ''.join(transposed_columns)
+    transposed = [transpose(r, transpositions) for r in rows]
+    if emptycolumnwise:
+        return combine_every_nth(transposed)
     else:
     else:
-        return combine_every_nth(transposed_columns)
+        return ''.join(chain(*transposed))
 
 def column_transposition_decipher(message, keyword, fillvalue=' ', 
       columnwise=False):
     """Deciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
 
 def column_transposition_decipher(message, keyword, fillvalue=' ', 
       columnwise=False):
     """Deciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
-
-    >>> column_transposition_decipher('hleolteher', 'clever')
-    'hellothere'
-    >>> column_transposition_decipher('hleolthre!e!', 'cleverly', fillvalue='?')
-    'hellothere!!'
-    >>> column_transposition_decipher('htleehoelr', 'clever', columnwise=True)
-    'hellothere'
     """
     """
+    # >>> column_transposition_decipher('hleolteher', 'clever')
+    # 'hellothere'
+    # >>> column_transposition_decipher('hleolthre!e!', 'cleverly', fillvalue='?')
+    # 'hellothere!!'
+    # >>> column_transposition_decipher('htleehoelr', 'clever', columnwise=True)
+    # 'hellothere'
+    # """
     transpositions = transpositions_of(keyword)
     if columnwise:
         columns = chunks(message, int(len(message) / len(transpositions)))
     transpositions = transpositions_of(keyword)
     if columnwise:
         columns = chunks(message, int(len(message) / len(transpositions)))