Skip to content

Instantly share code, notes, and snippets.

@cuihaoleo
Created March 21, 2016 00:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cuihaoleo/deb36a0d8386874d2a0a to your computer and use it in GitHub Desktop.
Save cuihaoleo/deb36a0d8386874d2a0a to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import binascii
import string
from collections import Counter
total_chars = 0
lines = []
result = []
with open("ciphers") as fin:
for line in fin:
s = line.strip()
lines.append(binascii.unhexlify(s))
result.append([None for c in s])
total_chars += len(s)
freq_table = [(' ', 0.183),
('e', 0.103),
('t', 0.075),
('a', 0.065),
('o', 0.062),
('i', 0.057),
('s', 0.053)]
char_count = Counter()
for char, freq in freq_table:
counter = Counter()
for i in range(len(lines)):
for j, b in enumerate(lines[i]):
if result[i][j] is not None:
del counter[(i, j)]
continue
for k in range(len(lines)):
if (len(lines[k]) > j):
xor_ed = chr(b ^ ord(char) ^ lines[k][j])
if xor_ed in string.ascii_lowercase or xor_ed == ' ':
counter += Counter({(i, j): 100})
elif xor_ed in string.ascii_uppercase:
counter += Counter({(i, j): 20 if j != 0 else 100})
elif ord(xor_ed) >= 128:
del counter[(i, j)]
break
elif xor_ed in {',', '.'}:
counter += Counter({(i, j): 20})
elif str.isprintable(xor_ed):
counter += Counter({(i, j): 5})
for (i, j), count in counter.most_common():
if result[i][j] == None and count > 0:
for k in range(len(lines)):
if (len(lines[k]) > j):
xor_ed = chr(lines[i][j] ^ ord(char) ^ lines[k][j])
char_count.update([xor_ed])
result[k][j] = xor_ed
if char_count[char] > total_chars*freq:
break
for i in range(len(lines)):
for j in range(len(lines[i])):
print(result[i][j] or '?', end='')
print()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment