desifrace vigenera
[krypto.git] / robot.py
1 #!/usr/bin/env python
2
3 """Mailove rozhrani pro sadu kryptoanalytickych nastroju."""
4
5 import sys
6 import smtplib
7 import email
8 from email.mime.text import MIMEText
9 from time import asctime
10 from ocesavac import ocesat
11 import jakobsen
12 from jakobsen import reference
13 import koincidence
14 import posuny
15 import pickle
16 import os
17 import re
18 from spolecne import ABECEDA
19 import vigenere
20
21 class settings:
22     pass
23
24 settings = pickle.load(open('./robot_settings'))
25 os.chdir(settings.path)
26
27 def posli_mail(komu, predmet, text, loguj=None):
28     msg = MIMEText(text)
29     msg['Subject'] = predmet
30     msg['From'] = settings.name + " <" + settings.mail  + ">"
31     msg['To'] = komu
32     smtplib.SMTP('localhost').sendmail(settings.mail, komu, msg.as_string())
33     if loguj:
34         soubor = open(loguj, 'w')
35         soubor.write(msg.as_string())
36         soubor.close()
37
38 # Cteni mailu
39 mail = email.message_from_file(sys.stdin)
40 predmet, _, opsny = mail['Subject'].strip().upper().partition(' ')
41 odesilatel = mail['From']
42 if predmet != settings.subject:
43     sys.exit()
44 if opsny == 'H':
45     posli_mail(odesilatel, "Napoveda", ''.join("Napoveda:\n"
46                "Prikazy robotovi vkladejte do predmetu zpravy "
47                "zaslane na adresu ", 
48                settings.mail, ".\nNa velikosti pismen nezalezi."
49                "\n\nSeznam prikazu:\n"
50                "\"", settings.subject, "\"   Analyza zpravy z tela mailu.\n" 
51                "\"", settings.subject, " L\" Opakovana analyza "
52                "posledni zpravy.\n",
53                "\"", settings.subject, " X\" Vynuti analyzu bez mezer.\n"
54                "\"", settings.subject, " M\" Vynuti analyzu s mezerami.\n"
55                "\"", settings.subject, " B\" Vypise cetnost vsech bigramu.\n"
56                "\"", settings.subject, " P\" Vypise vsechny posunuti textu.\n"
57                "\"", settings.subject, " A\" Vypise uplne vsechno co dava "
58                "alespon trochu smysl (nedoporucuji).\n"
59                "\"", settings.subject, " H\" Tato napoveda.\n"
60                "\nVolby (mimo \"H\") je mozno libovolne kombinovat.\n"
61                "Napriklad \"", settings.subject, " LXB\" analyzuje posledni "
62                "prijatou zpravu s vynucenim analyzy bez mezer a navic vypise "
63                "cetnosti bigramu.\n"
64                "\nS pozdravem\nVas Robot\n"))
65     sys.exit()
66 if 'L' in opsny:
67     mail = pickle.load(open('./msg_last.tmp'))
68     m1 = re.match(r".*\<(.*)\>.*", mail['From'])
69     m2 = re.match(r".*\<(.*)\>.*", odesilatel)
70     if m1:
71         f1 = m1.group(1)
72     else:
73         f1 = mail['From']
74     if m2:
75         f2 = m2.group(1)
76     else:
77         f2 = odesilatel
78     if (f1 != f2):
79         posli_mail(odesilatel, "Omluva", "Omlouvam se,"
80                    " ale Vase zprava uz bohuzel neni na serveru ulozena.\n")
81         sys.exit()
82 telo = mail.get_payload().strip()
83 if len(ocesat(telo, False)) < 2:
84     posli_mail(odesilatel, "Omluva", "Omlouvam se,"
85                    " ale Vase zprava je prilis kratka.\n")
86     sys.exit()
87 zprava = telo.upper()
88 analyza = []
89
90 # Puvodni zprava
91 analyza.append("Puvodni zprava:")
92 analyza.append(telo)
93
94 # Prepinani spacemodu
95 mod_m = False
96 mod_x = False
97 if 'X' in opsny:
98     mod_x = True
99 if 'M' in opsny:
100     mod_m = True
101 if 'A' in opsny:
102     mod_x = True
103     mod_m = True
104 if not mod_m and not mod_x:
105     if ' ' in ocesat(zprava, True)[1:-1]:
106         mod_m = True
107         analyza.append("\nAutomaticky zvolena analyza s mezerami.")
108     else:
109         mod_x = True
110         analyza.append("\nAutomaticky zvolena analyza bez mezer.")
111     
112 # Zakladni udaje
113 analyza.append("\nZakladni udaje:")
114 if mod_m:
115     analyza.append("Delka zpravy (vcetne mezer a zvlastnich znaku): " +
116                    str(len(zprava)))
117 analyza.append("Delka zpravy (bez mezer a zvlastnich znaku): " +
118                str(len(ocesat(zprava, False))))
119
120 # Prumerna delka slova
121 if mod_m:
122     analyza.append("\nPrumerna delka slova:")
123     slova = ocesat(zprava, True).split()
124     analyza.append('{0:.3}'.format(
125                    float(sum([len(word) for word in slova]))/len(slova)))
126
127 # Frekvence znaku 
128 analyza.append("\nFrekvencni analyza:")
129 freq = dict()
130 for char in ABECEDA:
131     freq[char] = 0
132 for char in zprava:
133     if char in freq:
134         freq[char] += 1
135 celkem = sum(freq.values())
136 for char in sorted(freq, key=freq.get, reverse=True):
137     analyza.append('{0} {1:>3} {2:>6.2%}'.format(char, freq[char],
138                    float(freq[char])/celkem))
139
140 # Index koincidence
141 if mod_m:
142     analyza.append("\nIndex koincidence (s mezerami):")
143     analyza.append('{0:.2%}'.format(
144                    koincidence.index_koincidence(zprava, True)))
145 if mod_x and len(zprava) >= 10:
146     #TODO tady by se spravne mela porovnavat delka ocesane zpravy
147     analyza.append("\nIndexy koincidence (bez mezer):")
148     analyza.append(koincidence.tabulka_indexu(zprava))
149
150 # Vigenere
151 if 'V' in opsny:
152     analyza.append("\nHeslo k Vigenerovi (" + opsny[-1] + "):")
153     vig_heslo, vig_text = vigere.vsechno(zprava, int(opsny[-1]))
154     analyza.append(vig_heslo)
155     analyza.append(vig_text)
156
157 # Jakobsen
158 if mod_m:
159     analyza.append("\nJakobsen (s mezerami):")
160     analyza.append(jakobsen.desifruj(zprava))
161 if mod_x:
162     analyza.append("\nJakobsen (bez mezer):")
163     analyza.append(jakobsen.desifruj(zprava, False))
164
165 # Posuny v abecede
166 (posun, posunuty_text) = posuny.nejlepsi(zprava)
167 if 'P' in opsny or 'A' in opsny:
168     analyza.append("\nPosuny v abecede (nejlepsi posun {0}):".format(posun))
169     analyza.append("\n".join("{0:>2} {1}".format(
170                    i + 1, posuny.vsechny(zprava)[i]) for i in range(26)))
171 else:
172     analyza.append("\nNejlepsi posun ({0}):".format(posun))
173     analyza.append(posunuty_text)
174
175 # Bigramy
176 if 'B' in opsny or 'A' in opsny:
177     analyza.append("\nBigramy podle cetnosti:")
178     bigramy = dict()
179     for i in ABECEDA:
180         for j in ABECEDA:
181             bigramy[i+j] = 0
182     for i in range(0, len(zprava)-1):
183         if zprava[i:i+2] in bigramy:
184             bigramy[zprava[i:i+2]] += 1
185     celkem = sum(bigramy.values())
186     for char in sorted(bigramy, key=bigramy.get, reverse=True):
187         if bigramy[char] == 0:
188             break
189         analyza.append('{0} {1:>3} {2:>6.2%}'.format(char, bigramy[char],
190                        float(bigramy[char])/celkem))
191
192 # Podpis a pozdrav
193 analyza.append(''.join(["\nS pozdravem\nVas Robot\n"
194                         "\n--\nPro napovedu zaslete mail s predmetem \"",
195                         settings.subject," H\".\n"]))
196
197 # Odeslani odpovedi
198 posli_mail(odesilatel,
199            "Analyza Vasi zpravy",
200            "\n".join(analyza),
201            './robot_last.tmp')
202
203 f = open('./msg_last.tmp', 'w')
204 pickle.dump(mail, f)
205 f.close()
206
207 f = open('./robot.log', 'a')
208 m = re.match(r".*\<(.*)\>.*", odesilatel)
209 if m:
210     odesilatel2 = m.group(1)
211 else:
212     odesilatel2 = odesilatel
213 f.write(asctime() + " " +  odesilatel2 + " " + opsny + "\n")
214 f.close()