-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathchallenge_3.py
72 lines (52 loc) · 2.3 KB
/
challenge_3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""
Orel Ben-Reuven
https://cryptopals.com/sets/1/challenges/3
The hex encoded string:
1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736
... has been XOR'd against a single character. Find the key, decrypt the message.
You can do this by hand. But don't: write code to do it for you.
How? Devise some method for "scoring" a piece of English plaintext. Character frequency is a good metric.
Evaluate each output and choose the one with the best score.
Achievement Unlocked
You now have our permission to make "ETAOIN SHRDLU" jokes on Twitter.
"""
import math
FREQ = {'a': 0.0651738, 'b': 0.0124248, 'c': 0.0217339, 'd': 0.0349835, 'e': 0.1041442, 'f': 0.0197881, 'g': 0.0158610,
'h': 0.0492888, 'i': 0.0558094, 'j': 0.0009033, 'k': 0.0050529, 'l': 0.0331490, 'm': 0.0202124, 'n': 0.0564513,
'o': 0.0596302, 'p': 0.0137645, 'q': 0.0008606, 'r': 0.0497563, 's': 0.0515760, 't': 0.0729357, 'u': 0.0225134,
'v': 0.0082903, 'w': 0.0171272, 'x': 0.0013692, 'y': 0.0145984, 'z': 0.0007836, ' ': 0.1918182}
def xor_bytes_const(b: bytes, const: int) -> bytes:
return bytes([const ^ _b for _b in b])
def bhattacharyya_distance(dist1: dict, dist2: dict) -> float:
bc_coeff = 0
for letter in FREQ.keys():
bc_coeff += math.sqrt(dist1[letter] * dist2[letter])
return -math.log(bc_coeff)
def score_string(word: bytes) -> float:
curr_freq = {letter: 0 for letter in FREQ.keys()}
# calc letter dist for current word
num_letters = 0
for i in word:
if chr(i).lower() in FREQ.keys():
curr_freq[chr(i).lower()] += 1
num_letters += 1
if num_letters != 0:
curr_freq = {letter: val / num_letters for letter, val in curr_freq.items()}
else:
return 0
# evaluate dist using the Bhattacharyya distance
distance = bhattacharyya_distance(FREQ, curr_freq)
return 1 / distance
if __name__ == '__main__':
src = bytes.fromhex('1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736')
max_score = 0
best_res = b''
for i in range(2 ** 8):
tmp = xor_bytes_const(src, i)
score = score_string(tmp)
if score > max_score:
max_score = score
best_res = tmp
print(best_res)
print(f'{max_score=}')
# b"Cooking MC's like a pound of bacon"