Skip to content

Commit 3028657

Browse files
committed
Add scripts for simple substitution and vignere cipher
1 parent 88855b8 commit 3028657

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed

sub.py

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from random import shuffle, randint, random
2+
from math import exp, log10
3+
4+
CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
5+
COUNT = 1000
6+
7+
8+
class ngram_score:
9+
'''
10+
Python 3 version of http://practicalcryptography.com/media/cryptanalysis/files/ngram_score_1.py
11+
'''
12+
def __init__(self, ngramfile, sep=' '):
13+
''' load a file containing ngrams and counts, calculate log probabilities '''
14+
self.ngrams = {}
15+
for line in open(ngramfile).readlines():
16+
key,count = line.split(sep)
17+
self.ngrams[key] = int(count)
18+
self.L = len(key)
19+
self.N = sum(self.ngrams.values())
20+
# calculate log probabilities
21+
for key in self.ngrams.keys():
22+
self.ngrams[key] = log10(float(self.ngrams[key])/self.N)
23+
self.floor = log10(0.01/self.N)
24+
25+
def score(self,text):
26+
''' compute the score of text '''
27+
score = 0
28+
ngrams = self.ngrams.__getitem__
29+
for i in range(len(text)-self.L+1):
30+
if text[i:i+self.L] in self.ngrams: score += ngrams(text[i:i+self.L])
31+
else: score += self.floor
32+
return score
33+
34+
def swap_chars(key):
35+
i = randint(0, 25)
36+
j = randint(0, 25)
37+
key[i], key[j] = key[j], key[i]
38+
return key
39+
40+
def decipher(cipher, key):
41+
freq_english = 'ETAOINSHRDLUWMFCGYPBKVJXQZ'
42+
d = []
43+
for c in cipher:
44+
d.append(freq_english[key.index(c)])
45+
return ''.join(d)
46+
47+
def crack_substitution(cipher):
48+
score = ngram_score('english_quadgrams.txt')
49+
bestkey, bestfit = None, -1 * float('inf')
50+
51+
itr = 0
52+
while True:
53+
parent = list(CHARS)
54+
shuffle(parent)
55+
pfit = score.score(decipher(cipher, parent))
56+
57+
itr = itr + 1
58+
for k in range(1000):
59+
child = parent.copy()
60+
child = swap_chars(child)
61+
cfit = score.score(decipher(cipher, child))
62+
if cfit > pfit:
63+
parent = child
64+
pfit = cfit
65+
66+
if pfit > bestfit:
67+
bestfit = pfit
68+
bestkey = parent
69+
print('[*] Iteration: ', itr)
70+
print('Best fitness so far:', pfit)
71+
print('Best key:', ''.join(parent))
72+
print('Plaintext:', decipher(cipher, parent), '\n')
73+
74+
75+
cipher = 'CGZNL YJBEN QYDLQ ZQSUQ NZCYD SNQVU BFGBK GQUQZ QSUQN UZCYD SNJDS UDCXJ ZCYDS NZQSU QNUZB WSBNZ QSUQN UDCXJ CUBGS BXJDS UCTYV SUJQG WTBUJ KCWSV LFGBK GSGZN LYJCB GJSZD GCHMS UCJCU QJLYS BXUMA UJCJM JCBGZ CYDSN CGKDC ZDSQZ DVSJJ SNCGJ DSYVQ CGJSO JCUNS YVQZS WALQV SJJSN UBTSX COSWG MTASN BXYBU CJCBG UWBKG JDSQV YDQAS JXBNS OQTYV SKCJD QUDCX JBXQK BMVWA SNSYV QZSWA LWAKB MVWAS ZBTSS QGWUB BGJDS TSJDB WCUGQ TSWQX JSNRM VCMUZ QSUQN KDBMU SWCJJ BZBTT MGCZQ JSKCJ DDCUE SGSNQ VUJDS SGZNL YJCBG UJSYY SNXBN TSWAL QZQSU QNZCY DSNCU BXJSG CGZBN YBNQJ SWQUY QNJBX TBNSZ BTYVS OUZDS TSUUM ZDQUJ DSICE SGNSZ CYDSN QGWUJ CVVDQ UTBWS NGQYY VCZQJ CBGCG JDSNB JULUJ STQUK CJDQV VUCGE VSQVY DQASJ UMAUJ CJMJC BGZCY DSNUJ DSZQS UQNZC YDSNC USQUC VLANB FSGQG WCGYN QZJCZ SBXXS NUSUU SGJCQ VVLGB ZBTTM GCZQJ CBGUS ZMNCJ LUDQF SUYSQ NSYNB WMZSW TBUJB XDCUF GBKGK BNFAS JKSSG QGWDC USQNV LYVQL UKSNS TQCGV LZBTS WCSUQ GWDCU JBNCS UESGN SUDSN QCUSW JBJDS YSQFB XUBYD CUJCZ QJCBG QGWQN JCUJN LALJD SSGWB XJDSU COJSS GJDZS GJMNL GSOJD SKNBJ STQCG VLJNQ ESWCS UMGJC VQABM JCGZV MWCGE DQTVS JFCGE VSQNQ GWTQZ ASJDZ BGUCW SNSWU BTSBX JDSXC GSUJS OQTYV SUCGJ DSSGE VCUDV QGEMQ ESCGD CUVQU JYDQU SDSKN BJSJN QECZB TSWCS UQVUB FGBKG QUNBT QGZSU QGWZB VVQAB NQJSW KCJDB JDSNY VQLKN CEDJU TQGLB XDCUY VQLUK SNSYM AVCUD SWCGS WCJCB GUBXI QNLCG EHMQV CJLQG WQZZM NQZLW MNCGE DCUVC XSJCT SQGWC GJKBB XDCUX BNTSN JDSQJ NCZQV ZBVVS QEMSU YMAVC UDSWJ DSXCN UJXBV CBQZB VVSZJ SWSWC JCBGB XDCUW NQTQJ CZKBN FUJDQ JCGZV MWSWQ VVAMJ JKBBX JDSYV QLUGB KNSZB EGCUS WQUUD QFSUY SQNSU'
76+
cipher = ''.join(cipher.split())
77+
crack_substitution(cipher)

vig.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
CSTHRES = 150
2+
ic_english = 0.0686
3+
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
4+
5+
6+
def chisquared(txt):
7+
expected = [0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150, 0.01974, 0.00074]
8+
expected = [x * len(txt) for x in expected]
9+
given = [0] * 26
10+
for c in txt:
11+
given[chars.index(c)] += 1
12+
cs = 0
13+
for i in range(26):
14+
cs = cs + (((given[i] - expected[i]) ** 2) / expected[i])
15+
return cs
16+
17+
def caesar(txt, k):
18+
ret = []
19+
for c in txt:
20+
ret.append(chars[(chars.index(c) + k) % 26])
21+
ret = ''.join(ret)
22+
return ret
23+
24+
def crack(cipher, klen):
25+
key = []
26+
strings = [''] * klen
27+
for i in range(len(cipher) // klen):
28+
for j in range(klen):
29+
try:
30+
strings[j] = strings[j] + cipher[i*klen + j]
31+
except IndexError:
32+
break
33+
for i in range(klen):
34+
for j in range(26):
35+
cs = chisquared(caesar(strings[i], j))
36+
if cs < CSTHRES:
37+
key.append(j)
38+
return key
39+
40+
def decrypt(cipher, key):
41+
plain = []
42+
for i, c in enumerate(cipher):
43+
plain.append(caesar(c, key[i % len(key)]))
44+
return ''.join(plain)
45+
46+
def IC(txt):
47+
given = [0] * 26
48+
for c in txt:
49+
given[chars.index(c)] += 1
50+
ic = 0
51+
for fi in given:
52+
ic += fi * (fi - 1)
53+
ic = ic / (len(txt) * (len(txt) + 1))
54+
return ic
55+
56+
57+
def cracklen(cipher):
58+
klenb = None
59+
for klen in range(1, 11):
60+
strings = [''] * klen
61+
for i in range(len(cipher) // klen):
62+
for j in range(klen):
63+
try:
64+
strings[j] = strings[j] + cipher[i*klen + j]
65+
except IndexError:
66+
break
67+
icavg = sum([IC(x) for x in strings]) / klen
68+
print(klen, icavg)
69+
if icavg > ic_english:
70+
klenb = klen
71+
break
72+
if not klenb:
73+
print('[*] Could not find key length!')
74+
else:
75+
return klenb
76+
77+
78+
cipher = 'SXULW GNXIO WRZJG OFLCM RHEFZ ALGSP DXBLM PWIQT XJGLA RIYRI BLPPC HMXMG CTZDL CLKRU YMYSJ TWUTX ZCMRH EFZAL OTMNL BLULV MCQMG CTZDL CPTBI AVPML NVRJN SSXWT XJGLA RIQPE FUGVP PGRLG OMDKW RSIFK TZYRM QHNXD UOWQT XJGLA RIQAV VTZVP LMAIV ZPHCX FPAVT MLBSD OIFVT PBACS EQKOL BCRSM AMULP SPPYF CXOKH LZXUO GNLID ZVRAL DOACC INREN YMLRH VXXJD XMSIN BXUGI UPVRG ESQSG YKQOK LMXRS IBZAL BAYJM AYAVB XRSIC KKPYH ULWFU YHBPG VIGNX WBIQP RGVXY SSBEL NZLVW IMQMG YGVSW GPWGG NARSP TXVKL PXWGD XRJHU SXQMI VTZYO GCTZR JYVBK MZHBX YVBIT TPVTM OOWSA IERTA SZCOI TXXLY JAZQC GKPCS LZRYE MOOVC HIEKT RSREH MGNTS KVEPN NCTUN EOFIR TPPDL YAPNO GMKGC ZRGNX ARVMY IBLXU QPYYH GNXYO ACCIN QBUQA GELNR TYQIH LANTW HAYCP RJOMO KJYTV SGVLY RRSIG NKVXI MQJEG GJOML MSGNV VERRC MRYBA GEQNP RGKLB XFLRP XRZDE JESGN XSYVB DSSZA LCXYE ICXXZ OVTPW BLEVK ZCDEA JYPCL CDXUG MARML RWVTZ LXIPL PJKKL CIREP RJYVB ITPVV ZPHCX FPCRG KVPSS CPBXW VXIRS SHYTU NWCGI ANNUN VCOEA JLLFI LECSO OLCTG CMGAT SBITP PNZBV XWUPV RIHUM IBPHG UXUQP YYHNZ MOKXD LZBAK LNTCC MBJTZ KXRSM FSKZC SSELP UMARE BCIPK GAVCY EXNOG LNLCC JVBXH XHRHI AZBLD LZWIF YXKLM PELQG RVPAF ZQNVK VZLCE MPVKP FERPM AZALV MDPKH GKKCL YOLRX TSNIB ELRYN IVMKP ECVXH BELNI OETUX SSYGV TZARE RLVEG GNOQC YXFCX YOQYO ISUKA RIQHE YRHDS REFTB LEVXH MYEAJ PLCXK TRFZX YOZCY XUKVV MOJLR RMAVC XFLHO KXUVE GOSAR RHBSS YHQUS LXSDJ INXLH PXCCV NVIPX KMFXV ZLTOW QLKRY TZDLC DTVXB ACSDE LVYOL BCWPE ERTZD TYDXF AILBR YEYEG ESIHC QMPOX UDMLZ VVMBU KPGEC EGIWO HMFXG NXPBW KPVRS XZCEE PWVTM OOIYC XURRV BHCCS SKOLX XQSEQ RTAOP WNSZK MVDLC PRTRB ZRGPZ AAGGK ZIMAP RLKVW EAZRT XXZCS DMVVZ BZRWS MNRIM ZSRYX IEOVH GLGNL FZKHX KCESE KEHDI FLZRV KVFIB XSEKB TZSPE EAZMV DLCSY ZGGYK GCELN TTUIG MXQHT BJKXG ZRFEX ABIAP MIKWA RVMFK UGGFY JRSIP NBJUI LDSSZ ALMSA VPNTX IBSMO'
79+
cipher = ''.join(cipher.split())
80+
klen = cracklen(cipher)
81+
print('[*] Key length:', klen)
82+
key = crack(cipher, klen)
83+
print('[*] Key:', key)
84+
print(decrypt('BELOSZ', key))

0 commit comments

Comments
 (0)