@SureshPatil/

Vigenere Cipher

Python

No description

fork
loading
Files
  • main.py
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#from subcipher import *
from math import gcd
from collections import Counter

def c2i(c, alphabet):
  return alphabet.index(c)
    #"""Returns the index of c in the string alphabet, starting at 0"""
    # Copy your method from subcipher.py here

def i2c(i, alphabet):
  return alphabet[i]
    #"""Returns the character at index i in alphabet"""
    # Copy your method from subcipher.py here

def prepare_string(s, alphabet):
  newS = ""
  for char in s:
    if char in alphabet.upper() or char in alphabet.lower(): 
      newS += char.upper()
  return newS
    #"""removes characters from s not in alphabet, returns new string"""
    # Copy your method from subcipher.py here

def vigenere_encode(plaintext, key, alphabet):
  encodeString = ""
  for i,char in enumerate(plaintext):
    encodeString += i2c((c2i(key[i%len(key)], alphabet) + c2i(char, alphabet))%len(alphabet), alphabet)
  return encodeString
  #"""Returns plaintext encoded by vigenere cipher using key"""

def vigenere_decode(ciphertext, key, alphabet):
  decodeString = ""
  for i,char in enumerate(ciphertext):
    decodeString += i2c((c2i(char, alphabet)- (c2i(key[i%len(key)],alphabet) + len(alphabet))%len(alphabet)), alphabet)
  return decodeString
  """Returns ciphertext decoded by vigenere cipher using key"""

def index_of_coincidence(ciphertext, alpha):
  alphCount = {}
  for letter in ciphertext:
    if letter not in alphCount:
      alphCount[letter] = 1
    else:
      alphCount[letter] += 1
  
  I = 0
  for letter in alphCount:
    I += ((alphCount[letter])/(len(ciphertext)))*((alphCount[letter] - 1)/(len(ciphertext) - 1))
  return I
  """Returns index of coincidence of a certain block of ciphertext"""

def friedman_test(ciphertext, alpha):
  I = index_of_coincidence(ciphertext, alpha)
  length = .0270*len(ciphertext)/((I*(len(ciphertext) - 1) + 0.0655 - 0.0385*len(ciphertext)))
  return length
  """Calls index_of_coincidence, then returns the predicted value for keyword length from the friedman test
  using that value"""

def kasiski_test(ciphertext):  #Code partially provided
  
  """Finds gcd of most common distances between repeated trigraphs
  Recommended strategy: loop through the ciphertext, keeping a list of trigraphs and a list of distances in this way:
  1) When encountering a new trigraph add it to the trigraph list
  2) When encountering a repeat add the distance from current index to first index of that trigraph to the list of distances"""
    # Here, write code to create the array of distances:
  trigraphList = {}
  distanceList = []
  for index in range(len(ciphertext) - 2):
    if ciphertext[index:index + 3] not in trigraphList:
      trigraphList[ciphertext[index:index + 3]] = index
    else:
      distanceList.append(index - trigraphList[ciphertext[index:index + 3]])
    # Code is provided to find the gcd of any common distances appearing at least twice, just add your array:
  dCount = Counter(distanceList)# put your array of distances here)
  topCount = dCount.most_common(6)
  my_gcd = topCount[0][0]
  for index in range(1, len(topCount)):
    if topCount[index][1] > 1:
      my_gcd = gcd(my_gcd, topCount[index][0])
  return my_gcd

def run_key_tests(ciphertext, alphabet): #Code provided
    """Runs Friedman and Kasiski tests and formats the output nicely"""
    friedman = friedman_test(ciphertext, alphabet)
    kasiski = kasiski_test(ciphertext)
    out = "Friedman test gives: " + str(friedman) + " and Kasiski gives this as the most likely: " + str(kasiski);
    return out

def make_cosets(text, n):
  cosetList = ['']*n
  for index,char in enumerate(text):
    cosetList[index%n] += char
  #print(cosetList)
  return cosetList
  

def rotate_list(old_list):  #Code provided
    """Takes the given list, removes the first element, and appends it to the end of the list, then returns the
    new list"""
    new_list = old_list[:]
    new_list.append(old_list[0])
    del new_list[0]
    return new_list

def find_total_difference(list1, list2):
  sumOfDifferences = 0
  for x in range(len(list1)):
    sumOfDifferences += abs(list2[x] - list1[x])
  return sumOfDifferences
  """Takes two lists of equal length containing numbers, finds the difference between each pair of matching
  numbers, sums those differences, and returns that sum"""

def find_likely_letters(coset, alpha, eng_freq, ciphertext):
  """Finds the most likely shifts for each coset and prints them
  Recommended strategy: make a list of the frequencies of each letter in the ciphertext, in order, A to Z.
  Then, alternate using the find total difference method (on your frequencies list and the standard english
  frequencies list) and the rotate list method to fill out a new list of differences.  This makes a list of
  the total difference for each possible encryption letter, A to Z, in order.
  Then, find the indices of the smallest values in the new list, and i2c them for the most likely letters."""

  coset_freq = []
  for letter in alpha:
    coset_freq.append(coset.count(letter)/len(coset))
  totalDistanceList = []
  
  for x in range(len(alpha)):
    totalDistanceList.append(find_total_difference(coset_freq, eng_freq))
    coset_freq = rotate_list(coset_freq)
  #print(totalDistanceList)
  newList = totalDistanceList[:]
  newList.sort()
  #print(newList)
  #print(totalDistanceList.index(newList[0]))
  letter1 = i2c(totalDistanceList.index(newList[0]), alpha)
  letter2 = i2c(totalDistanceList.index(newList[1]), alpha)

    #return statement provided.  feel free to replace "letter1" and "letter2" with other variable names.
  return "the most likely letter is: " + letter1 + " followed by: " + letter2

def crack(ciphertext, alpha, eng_freq):  #Code provided
    """User-friendly walkthrough of decoding methods"""
    print("Your cipher text is: " + ciphertext)
    out = run_key_tests(ciphertext, alpha)
    print(out)
    x = int(input("Choose the key length you'd like to try: "))
    cosets = make_cosets(ciphertext, x)
    for index in range(len(cosets)):
        print("For coset " + str(index + 1) + ", " + find_likely_letters(cosets[index], alpha, eng_freq, ciphertext) + ".")
    s = input("Type the key you would like to use to decipher: ")
    print(vigenere_decode(ciphertext, s, alpha))
    print()




alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

eng_freq = [.0817, .0149, .0278, .0425, .1270, .0223, .0202, .0609, .0697, .0015, .0077, .0403, .0241, .0675, .0751,
            .0193, .0010, .0599, .0633, .0906, .0276, .0098, .0236, .0015, .0197, .0007]

example = "UZRZEGNJENVLISEXRHLYPYEGTESBJHJCSBPTGDYFXXBHEEIFTCCHVRKPNHWXPCTUQTGDJHTBIPRFEMJCNHVTCFSAIIJENREGSALHXHWZWRZXGTTVWGDHTEYXISAGQTCJPRSIAPTUMGZALHXHHSOHPWCZLBRZTCBRGHCDIQIKTOAAEFTOPYEGTENRAIALNRXLPCEPYKGPNGPRQPIAKWXDCBZXGPDNRWXEIFZXGJLVOXAJTUEMBLNLQHGPWVPEQPIAXATYENVYJEUEI"
# For the example, the key is "PLANET" and the plaintext is:
#"For many years the known planets of our solar system were mercury, venus, earth, mars, jupiter, saturn, uranus, neputne, and pluto.  However, it is now true that many people think pluto should no longer be considered a named planet.  New planets are currently being discovered, and it is very likely that many more will be in the near future."

#Try this:
# crack(example, alpha, eng_freq)

#Once everything works, uncomment the following six lines and crack some ciphertexts!
c1 = "RVCQWMYFULRIKPFMQEMTJJOCLHYVHNFONGOGUFCRWHEPYAOOQSQCBYCRGMFYRSMRQUQSMYBXGKULHCRHIZSMSTZGQCCBNJMFMBARVURHBGGQFCFCHBGBAUCLIGQGHBMINPSFWWHECHPOHBCGAVULQYRCJPCXSQYECIBRCQHLGPORWILGQGHBQAUJZVGHMMTNCLNGHNPIFWBYCRMRCVCEOGHYJCHEWHMHBCFYYFFGSLRSMRGGWDFYWHRSRRKUQHIMGBMFNYBXGHGYRYZCNFTLGSXKOHYBXIOMGGEGTLCOEMINYBXEWPCHYPFCZZYYBMUSLQ"
c2 = "EFMREXHTGRQQVDODIPQSIVVNURSUVVNGNXRRIOIBEPOZNISWDRIOEOWVVYAVVIDFJFTYQDPFRKQMQCCFQBQXNRTKYRRHRCQWTXVZNIZVRDCEODSHZVCWDEENVCQWTXVVRRBSJTRMUZVRIIAOWMQIZNXYPYGJAEDMYKKIGCWXEYAUKRDNPSKCHHXVLQZMQILNFOVVVRNFSRJIVNGBEWKEGCVKRTZTJWWYGIIHSGDVZOPYJUGHUKBIPGETUYJDNXOTSXKOJIPMPXFZNIDLHKICQBVHEKNGCWDPURGCSXTTEUMSQULMRDMRPRNFSQSNVMGXXDVZOPMSPOFNNIVHHVRTOHWQRSEYHLPXOHKPJQIIVRQVKEAVKVJGKPTYKUCDMKXKOCEGWKKHUFUTMIFQUEKCAUKKTGXMQQEEQBQRTVPTYKUCDMKXKOCEGWKKHUKHGZYURFSGYJSTFGTKQPKEGKCXRHZNFKWHSLEPMIRHZNUDVXEKIQXWWJRTYSPOCLTQWEWGGETPSUOZNIKWSGTIHSGWCJKQBWRNMIPQEJKMEPZVRDCEODLHRIOEOWVQWPTYKUCDMKXKWJLSQPXHPIESEMUGJEZZIUVZSGSRPCEYFSJIGIEPDWXDAEEDWLPTLWNMQIBNQGPHFXEQPXKGRPRVMFCKIQXHRORIPCTHEZANSDHFRLIYVLVYMUKRGHFROKPOQXIEBIOCKEFDEVMJIPMPXFVTGCXLPXDGLYJIZNIKRGORIPDELPZNIDLHUFUTMIFQUEKWTOGDEPDEWKFNQPXKGSUKVHVAJTGWEQFDAPKKHOVNVYJGGIIXOHDTKIHKGWUJUEREVORCJSRHEFDGYJFQDPWDIURIOIBEPUKHGCIPKXHVLIFQESKNIUGUPCBXRHKHGZVRIIAOWMQIGRQMIVUSUVYJWGETJOXHTDSQPXZCIEFOZHNFPOORWKJUUOHIQITJSWOCIGGBTUQTEUCALVYTJOXHTDPTYKUCDMKXKLOGLGWIQVRTKYRRTTOFSRJTVSGBZHFWOTDLHCTTWKPZTZTKXKRHJOWBGHEFDGCSIVNATOIQIZNGOVLPXCQWFLPVSGXKLPVETSRJVVCJXMTWVSYSXKUFFVGEUGUEXOPRRDEPDTUCTTKMIV"
c3 = "OPKLNPCAVGYQRPKSAJUMYIUGVJHETIRRYWRHEEXQVBYEGSEIZVJSSMKEXWRSHVVHKWYXRVKSJTGVTIWSMQTHBSIHDAVPNCYEYJKIAXRGFMJXBXYIRIRPVXUIKQIXRHJMHXRCNRVRJZSSHWWEXMSSEIKLVVGQRXIIRQJIGLVJVKKSSEDEIWLEOSLXAWXXLJZZZEOXUEYIVDEFYETOHWAWGETLZITHEYXKZLRCUEEHNWSISIRXPZKWJMEWOWTQNHVJJZZLRWKEDZYMGARWIWAWRXICDVMXUICMABKZRRRXOPKFRWKSABOQRWZXRIYWRPUSHEUVXMEKVVJEGTIINMTXGLVIGMIXEMTGPZXIAXNENKAXBJWHPZORTHRCGQMLGLFYMAOXJEJTVZZSSXYIZKURBQPHMQBIVRGVZXGVNXZSINUVUEKIRMKOGLVJGIZANWJIQMTJYMXLOAATNRUADVYXBRNLJEGWGLZVOGTMAIRRYPGHNZRVDKUWRYCGZZGFBZVLDAXMTLKEISRIJIEXNTUAYCIINBORTWVZZZGPGMDINWTXUINETWTINGYPVVJMAKFTKWYMGIKLZTOJGWYEABZLRTFWOMXAVXYXCMKRBVDSPALEPIXEUMJJESDXCMCEYPZXRIYSAIFJOPUWRTZGOCXIFAYMXPGVRWFGJVZVVZVHOPGXGLVITMYJBPCSRGUYNFFYOENIACFYHWBIOMXFMWZLRVZWRIZGUMEKTWAXUITEKBOSAFVRZIZLVXIEI"
# crack(c1, alpha, eng_freq)
# crack(c2, alpha, eng_freq)
# crack(c3, alpha, eng_freq)

c4 ="VRNQWALVVMASNBHALVFBGAPAHPGKMNDMINKPTZVPACRVJZFWJGJFXRMIWCNSNVQDTAPZUYDOKRRVVGKXWLVJGAQADLVVTEUNNISTLOETNTODLYEHEHOAEDSYGNROMOAIWIMYWPNOAHWTAMITRTKIKQLEFCZPYCWARXIXYVEZQTNMLMYLVLIRSXROKZRSCIHGKMZLQXZGWHMVZZMSLGFRSCIHGJQTKMAWIVWIEUYWWITKMLCXZWEGEVNAQRSUIIHSXXWLPGHNUBKQWXLHJBNLFIIIOVSLKDHVLZOTXITFHRMLPGHAOZPSZZOTLIRMTTWOUMSVKCXVGUUXWNOUTPKRHLWIBLKEOKFXWGUBKIIJAAEBIVKVMIAECQLHGCWTLYMVJZTGWJLPSZJAAIMTABVMISTWAMLMWPGSYEXUPGXWTAAIQXMBRIRHOIZGNXXPKJHHMCVKHACPEPJKJEIIXSRMLKUMMNOLWAPKURSCLPGHWTLWMZKJMQMYZTKMSLHRBNLVPIYZLPIIRIEOKAHIIXURSCXOTPNVVBRBJVGSBJPKIKZTXWAGNXQZKJDITJPKIKZTXWAGNXQMVSXEAKUHXMZOTXITFFIAYHZIBNHMHWKZGXCYLMLMYATRLGYWXEKUMCAOEEIBZLKETVOTFMZBLIAZOXWISLTPXNHUIBGZJYMYABSVZDHSVZOXGWSWNXMXZXGBOVGSNEVNVZYHMIAZAAINOYLXBCVFIAYHZIAUUMLQYWTKMCPEPTKHWCWAAHXWJHRWKUKXAWXKLEVJAAITGZMQMYZTKMCPEPOOCXCWAJKYKOHEGTALLJWXAAYZYKTCAIVWIEUYWWGUBAEDKBGXQRAAIMTKHJKRHLWBNBKWLGFMSBAYGMVGZFEVEVYXPKZBBKUKXAWXKLEAVVLWQHSXCWATTCEOZAXWQUHABNHMXPKMBVAZAPSKOWAIZYVGXPOZIEOKLTGPNHOIAUTXXPOUZMVIVFQWTDBXPZOBWWTLTPAUAAIXRHBRBKEMSNZOXPIYAFIAYHZIWTAAMAVHZIJKNBRACPMLBNLLIBCVPSZJZMAWOTISZZHGXHVQTKSSTAGGDUZKEMEOEEMHVPTZUTDFRYMYAGDZETXFBUFUGBRZUTDFRHIRDRVUGCY"
c4 = prepare_string(c4, alpha)
crack(c4, alpha, eng_freq)