Code
Writeup from chall4
One of the 60-character strings in this file has been encrypted by single-character XOR.
Find it.
(Your code from #3 should help.)
code:
import math
from collections import Counter
from string import ascii_lowercase
def get_freq(txt: str, letters: str) -> dict:
txt = txt.lower()
count = Counter(txt)
total = sum(count[c] for c in letters)
return {letter: count[letter] / total for letter in letters}
with open("pg84.txt") as f:
data = f.read()
freq = get_freq(data, ascii_lowercase + " ")
print(freq)
def xor_bytes_const(txt: bytes, const: int) -> bytes:
return bytes([const ^ b for b in txt])
def bhattacharyya_distance(freq1: dict, freq2: dict) -> float:
bt_cof = 0.0
for letter in freq1:
bt_cof += math.sqrt(freq1[letter] * freq2[letter])
return -math.log(bt_cof)
def string_scoring(word: bytes) -> float:
cur_freq = {letter: 0 for letter in freq}
num_letter = 0
for i in word:
if chr(i).lower() in cur_freq:
cur_freq[chr(i).lower()] += 1
num_letter += 1
if num_letter != 0:
cur_freq = {letter: val / num_letter for letter, val in cur_freq.items()}
else:
return 0
distance = bhattacharyya_distance(freq, cur_freq)
return 1 / distance
with open("chall.txt") as f:
chunks = set(f.read().split())
def decode_single_byte_xor_cypher(word: str) -> (bytes, int, int):
src = bytes.fromhex(word)
max_score = 0
best_res = b""
best_key = None
for i in range(2**8):
candidate = xor_bytes_const(src, i)
score = string_scoring(candidate)
key = i
if score > max_score:
max_score = score
best_res = candidate
best_key = key
return best_res, max_score, best_key
if __name__ == "__main__":
with open("chall.txt") as fh:
Lines = fh.readlines()
max_score = 0
best_word = b""
best_key = None
for line in Lines:
tmp_word, tmp_score, tmp_key = decode_single_byte_xor_cypher(line)
if tmp_score > max_score:
max_score = tmp_score
best_word = tmp_word
best_key = tmp_key
print("****************************************************************")
print(best_word.strip().decode())
print(f"{max_score}")
print(f"{best_key}")
print("****************************************************************")
Output:
{'a': 0.0637471187103264, 'b': 0.011968525709327632, 'c': 0.022106374711871032, 'd': 0.04018192349773668, 'e': 0.10987397411785459, 'f': 0.020790575828869867, 'g': 0.014254487899179295, 'h': 0.04710893718252181, 'i': 0.058584038310724, 'j': 0.0011966142015699007, 'k': 0.004195300786380528, 'l': 0.03032535034337107, 'm': 0.025136049313853787, 'n': 0.058064393099683684, 'o': 0.060197798897303326, 'p': 0.014623960411616215, 'q': 0.0007723167356745972, 'r': 0.049761988191181765, 's': 0.05047471258614073, 't': 0.07241661243763661, 'u': 0.024819018061246624, 'v': 0.009127162904006274, 'w': 0.018242407339869423, 'x': 0.0016137605865793282, 'y': 0.018886004619598253, 'z': 0.0005077267428971889, ' ': 0.1710228667729794}
****************************************************************
Now that the party is jumping
7.943424979642356
53
****************************************************************