2021-12-29 17:11:42 +01:00
|
|
|
from c2 import fixed_xor
|
|
|
|
from collections import Counter
|
|
|
|
|
2022-01-04 21:42:30 +01:00
|
|
|
def frequency_table():
|
|
|
|
with open('alice.txt', 'r') as f:
|
|
|
|
chars = {}
|
|
|
|
while True:
|
|
|
|
l = f.readline()
|
|
|
|
if not l: break
|
|
|
|
for c in l:
|
|
|
|
chars[c] = chars.get(c, 0) + 1
|
|
|
|
result = {}
|
|
|
|
for c, n in chars.items():
|
|
|
|
result[c] = n / len(chars)
|
|
|
|
return result
|
2021-12-29 17:11:42 +01:00
|
|
|
|
2022-01-04 21:42:30 +01:00
|
|
|
def score(bs, freqs):
|
|
|
|
return sum(freqs.get(b, 0) for b in bs)
|
2021-12-29 17:11:42 +01:00
|
|
|
|
|
|
|
def decode_cipher(x):
|
2022-01-04 21:42:30 +01:00
|
|
|
freqs = frequency_table()
|
|
|
|
|
|
|
|
if not freqs:
|
|
|
|
raise Error("Cannot decode cipher without a populated frequency table")
|
|
|
|
|
2021-12-29 17:11:42 +01:00
|
|
|
x = bytearray.fromhex(x)
|
|
|
|
num_bytes = len(x)
|
|
|
|
|
|
|
|
mx, result, key = 0, None, None
|
2022-01-04 21:42:30 +01:00
|
|
|
for b in range(0, 1 << 8):
|
|
|
|
mask = bytearray(b.to_bytes(1, 'big') * num_bytes)
|
|
|
|
try:
|
|
|
|
y = fixed_xor(x, mask, decode_hex=False, encode_hex=False).decode('ascii')
|
|
|
|
except:
|
|
|
|
continue
|
|
|
|
test = score(y, freqs)
|
2021-12-29 17:11:42 +01:00
|
|
|
if test > mx:
|
|
|
|
result = y
|
|
|
|
mx = test
|
|
|
|
key = mask.decode('ascii')
|
|
|
|
return result
|
|
|
|
|
|
|
|
run_tests = False
|
|
|
|
if run_tests:
|
|
|
|
print(decode_cipher("1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736"))
|
2022-01-04 21:42:30 +01:00
|
|
|
|
|
|
|
################################################################################
|
|
|
|
# Answer
|
|
|
|
################################################################################
|
|
|
|
"Cooking MC's like a pound of bacon"
|