Advertisement
Guest User

Untitled

a guest
May 26th, 2018
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.18 KB | None | 0 0
  1. import operator
  2. import math
  3.  
  4. def frequencyAnalysis(ciphertext):
  5.     letterDict = {}
  6.     for c in ciphertext:
  7.         if c in letterDict:
  8.             letterDict[c] += 1
  9.         else:
  10.             letterDict[c] = 1
  11.     digramDict = {}
  12.     trigramDict = {}
  13.  
  14.     for i in range(len(ciphertext)):
  15.         if i + 2 > len(ciphertext):
  16.             break
  17.         if ciphertext[i:i+2] in digramDict:
  18.             digramDict[ciphertext[i:i+2]] +=1
  19.         else:
  20.             digramDict[ciphertext[i:i+2]] = 1
  21.  
  22.     for i in range(len(ciphertext)):
  23.         if i + 3 > len(ciphertext):
  24.             break
  25.         if ciphertext[i:i+3] in trigramDict:
  26.             trigramDict[ciphertext[i:i+3]] +=1
  27.         else:
  28.             trigramDict[ciphertext[i:i+3]] = 1
  29.     sortedDict = sorted(letterDict.items(), key=operator.itemgetter(1))
  30.     sortedDigramDict = sorted(digramDict.items(), key=operator.itemgetter(1))
  31.     sortedTrigramDict = sorted(trigramDict.items(), key=operator.itemgetter(1))
  32.  
  33.     print("""
  34.            -----------------------------------------------------------------------
  35.            |                                                                     |
  36.            |                       Letter frequencies                            |
  37.            |                                                                     |
  38.            -----------------------------------------------------------------------""")
  39.     print(sortedDict)
  40.  
  41.     print("""
  42.            -----------------------------------------------------------------------
  43.            |                                                                     |
  44.            |                   END OF LETTER FREQUENCIES                         |
  45.            |                                                                     |
  46.            -----------------------------------------------------------------------""")
  47.     print("""
  48.            -----------------------------------------------------------------------
  49.            |                                                                     |
  50.            |                     Digram Frequencies                              |
  51.            |                                                                     |
  52.            -----------------------------------------------------------------------""")
  53.     print(sortedDigramDict)
  54.     print("""
  55.            -----------------------------------------------------------------------
  56.            |                                                                     |
  57.            |                  END OF DIGRAM FREQUENCIES                          |
  58.            |                                                                     |
  59.            -----------------------------------------------------------------------""")
  60.     print("""
  61.            -----------------------------------------------------------------------
  62.            |                                                                     |
  63.            |                       Trigram Frequencies                           |
  64.            |                                                                     |
  65.            -----------------------------------------------------------------------""")
  66.     print(sortedTrigramDict)
  67.     print("""
  68.            ------------------------------------------------------------------------
  69.            |                                                                      |
  70.            |                      END OF TRIGRAM FREQUENCIES                      |
  71.            |                                                                      |
  72.            ------------------------------------------------------------------------""")
  73.  
  74. def shiftBreaker(ciphertext):
  75.  
  76.     for i in range(0, 26):
  77.        
  78.         decoder = ''
  79.         for c in ciphertext:
  80.             decoder = decoder + chr(97 + (ord(c) - i) % 26)
  81.         print('-' + str(i) + ':\t' + decoder + '\n')
  82.  
  83. def rotate(array):
  84.     array = array[-1:] + array[:-1]
  85.     return array
  86.  
  87. def count_letters(text):
  88.     # Create a list that can hold one value for each letter in the alphabet
  89.     freq_list = [0] * 26
  90.     for c in text: # For every letter add one to its spot in the freq_list
  91.         if c.isalpha():
  92.             c = c.lower()
  93.             freq_list[ord(c) - ord('a')] += 1
  94.     return freq_list
  95.  
  96. def index_of_coincidence(freq_list):
  97.     # Get the total number of letters
  98.     N = sum(freq_list)
  99.     f_sum = 0
  100.     for i in freq_list: # Calculate this sum: Ei(Ei - 1)
  101.         f_sum += i * (i - 1)
  102.     return f_sum /  (N * (N - 1)) # Return this: sum(Ei(Ei-1)) / (N(N-1))
  103.  
  104. def approximate_key_length(ic_eng, ic_rand, ic_cipher, N):
  105.     t = 0.0265 * N
  106.     n = (ic_eng - ic_cipher) + N * (ic_cipher - ic_rand)
  107.     return t / n
  108.  
  109. def shift_string(steps, text):
  110.     # Store values for the first and last letter in the alphabet
  111.     a_val = ord('a')
  112.     z_val = ord('z')
  113.     out_text = ''
  114.     for c in text: # For every letter add the steps
  115.         if c.isalpha():
  116.             c = c.lower()
  117.             new_c_val = ord(c) - steps
  118.             while new_c_val < a_val:
  119.                 new_c_val = (z_val + 1) - (a_val - new_c_val)
  120.             while new_c_val > z_val:
  121.                 new_c_val = (a_val - 1) + (new_c_val - z_val)
  122.             out_text += chr(new_c_val)
  123.     return out_text
  124.  
  125. def goodness_of_fit(text, actual_freqs):
  126.     freqs = count_letters(text)
  127.     N = sum(freqs)
  128.     freqs = [ x / N for x in freqs ] # Get the probabillity for every letter
  129.     N = sum(actual_freqs)
  130.     a_freqs = [ x / N for x in actual_freqs ] # Get the probabillity for every letter
  131.     res = 0
  132.     for i in range(0, len(a_freqs)): # Calculate this: sum(((Fi-Ai)^2)/Ai)
  133.         res += ((freqs[i] - a_freqs[i]) * (freqs[i] - a_freqs[i])) / a_freqs[i]
  134.     return res
  135.  
  136. def find_key(key_length, text, actual_freqs):
  137.     columns = [''] * key_length # Create columns for every letter in the key
  138.     current_column = 0
  139.     for c in text: # Add the letters to the columns with their pos % key_length
  140.         if c.isalpha():
  141.             columns[current_column] += c
  142.             current_column += 1
  143.             if current_column >= key_length:
  144.                 current_column = 0
  145.  
  146.     key = ''
  147.     fit_list = []
  148.     for col in columns: # For every column
  149.         fit = 1000000000 # Set Fittnes at a large value
  150.         i_val = 0 # Index of best fittnes
  151.         for i in range(0, 26): # 26 possible shifts
  152.             shift_col = shift_string(i, col) # Shift the column
  153.             # Get the fittnes of the shifted column
  154.             cur_fit = goodness_of_fit(shift_col, actual_freqs)
  155.             # If the fittnes is better then the last fittnes then this is the new fittnes
  156.             if cur_fit < fit:
  157.                 fit = cur_fit
  158.                 i_val = i
  159.  
  160.         # Add the shift letter to the key
  161.         key += chr(ord('a') + i_val)
  162.         # Store the best fittnes for this column
  163.         fit_list.append(fit)
  164.  
  165.     # Return the key with the avrage of the fittnes
  166.     return (key, sum(fit_list) / float(len(fit_list)))
  167.  
  168. def get_plain_text(text, key):
  169.     current_key_letter = 0
  170.     out_text = ''
  171.     for c in text:
  172.         if c.isalpha(): # For every letter shift it according to the key
  173.             out_text += shift_string(ord(key[current_key_letter]) - ord('a'), c)
  174.             current_key_letter += 1
  175.             if current_key_letter >= len(key):
  176.                 current_key_letter = 0
  177.         else:
  178.             out_text += c
  179.     return out_text
  180.  
  181. def chiSquaredTest(ciphertext, keyLength):
  182.  
  183.     frequencies = [ 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153,
  184.                    0.00772, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056,
  185.                    0.02758, 0.00978, 0.02360, 0.00150, 0.01974, 0.00074]
  186.     columns = [''] * keyLength
  187.  
  188.     for c in range(0, len(ciphertext), keyLength):
  189.          
  190.         for i in range(keyLength):
  191.             if c + i >= len(ciphertext):
  192.                 break
  193.             columns[i] = columns[i] + ciphertext[c + i]
  194.  
  195.     for i in range(len(columns)):
  196.         obs = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0, 'f': 0, 'g': 0, 'h': 0, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'n': 0, 'o': 0, 'p': 0, 'q': 0, 'r': 0, 's': 0, 't': 0, 'u': 0, 'v': 0, 'w': 0, 'x': 0, 'y': 0, 'z': 0}
  197.         for c in columns[i]:
  198.             obs[c] += 1
  199.        
  200.         N = len(columns[i])
  201.         print(obs)
  202.         chiSquareValue = [0] * 26
  203.        
  204.         for j in range(26):
  205.             counter = 0
  206.             for o, c in obs.items():
  207.                 #print(str(frequencies[counter] * N) + ' vs ' + str(c))
  208.                 chiSquareValue[j] = chiSquareValue[j] + float((math.pow(float(c) - frequencies[counter] * N, 2)) / (frequencies[counter] * N))
  209.                 counter += 1
  210.             frequencies = rotate(frequencies)
  211.        
  212.         print("Goodnes of fit:\n")
  213.  
  214.         counter = 0
  215.         for c in chiSquareValue:
  216.             print('Shift ' + str(counter) + ':\t' + str(c))
  217.             counter += 1
  218.            
  219.  
  220. def main():
  221.    
  222.     print("please enter the ciphertext. Hit enter and then Crtl + D to save it :)")
  223.  
  224.     userInput = []
  225.     while True:
  226.         try:
  227.             line = input()
  228.         except EOFError:
  229.             break
  230.         userInput.append(line)
  231.  
  232.    
  233.     cipher = ''
  234.     for i in range(len(userInput)):
  235.         for u in userInput[i]:
  236.             if u == ' ':
  237.                 continue
  238.             else:
  239.                 cipher = cipher + u
  240.  
  241.     cipher = cipher.lower()
  242.     done = False
  243.  
  244.     # Read an example english text from a file
  245.     example_file = open('example_text.txt', 'r')
  246.     ex_text = example_file.read()
  247.     example_file.close()
  248.  
  249.     # Calculate frequency of the english text
  250.     ex_freq_list = count_letters(ex_text)
  251.  
  252.     # Calculate index of coincidence of the english text
  253.     ex_ic = index_of_coincidence(ex_freq_list)
  254.    
  255.     while not done:
  256.         selection = input("""What would you like to do?
  257.  
  258.            1- Decode a shift cipher
  259.            
  260.            2- perform a frequency analysis
  261.  
  262.            3- Perform a chi-squared test
  263.  
  264.            4- Decode a viginére cipher
  265.            """)
  266.         if selection == '1':
  267.             done = True
  268.             shiftBreaker(cipher)
  269.            
  270.         elif selection == '2':
  271.             done = True
  272.             frequencyAnalysis(cipher)
  273.            
  274.         elif selection == '3':
  275.             done = True
  276.             keyLength = int(input('Enter key length:\n'))
  277.  
  278.             chiSquaredTest(cipher, keyLength)
  279.         elif selection == '4':
  280.             # Calculate frequency of the cipher text
  281.             cipher_freq_list = count_letters(cipher)
  282.  
  283.             # Calculate index of coincidence of the cipher text
  284.             cipher_ic = index_of_coincidence(cipher_freq_list)
  285.  
  286.             # Approximate the key length using 0.0385 as the
  287.             # index of coincidence of random text
  288.             key_len = approximate_key_length(ex_ic, 0.0385, cipher_ic, \
  289.                 sum(cipher_freq_list))
  290.             print(key_len)
  291.  
  292.             # Round the key length to an integer
  293.             key_len = int(key_len + 0.5)
  294.  
  295.             # Get a key with the approximate key length
  296.             key, key_fit = find_key(key_len, cipher, ex_freq_list)
  297.  
  298.             # Get a key with the approximate key length + 1
  299.             k, f = find_key(key_len + 1, cipher, ex_freq_list)
  300.             if key_fit > f: # If the avrage fittnes of this key is better than the last one switch them
  301.                 key = k
  302.                 key_fit = f
  303.  
  304.             # Get a key with the approximate key length - 1
  305.             k, f = find_key(key_len - 1, cipher, ex_freq_list)
  306.             if key_fit > f: # If the avrage fittnes of this key is better than the last one switch them
  307.                 key = k
  308.                 key_fit = f
  309.  
  310.             # Print the key with the best fittnes and then decipher the text
  311.             print(key)
  312.             print(get_plain_text(cipher, key))
  313.  
  314.             key = input('Try a different key: ')
  315.             print(key)
  316.             print(get_plain_text(cipher, key))
  317.         else:
  318.             print('Please enter a valid character!')
  319.  
  320. if __name__ == '__main__':
  321.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement