-
Notifications
You must be signed in to change notification settings - Fork 4
/
p56.py
59 lines (42 loc) · 1.58 KB
/
p56.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
from base64 import b64decode
from operator import itemgetter
from os import urandom
from typing import Dict
from main import Solution
from Crypto.Cipher import ARC4
cookie = b64decode('QkUgU1VSRSBUTyBEUklOSyBZT1VSIE9WQUxUSU5F')
def _rc4_encryption_oracle(request: bytes) -> bytes:
fresh_key = urandom(16)
cipher = ARC4.new(fresh_key)
return cipher.encrypt(request + cookie)
def p56() -> str:
cookie_len = len(_rc4_encryption_oracle(b''))
z16, z32 = 15, 31
z16_bias, z32_bias = 0xf0, 0xe0
plaintext = ['?'] * cookie_len
for i in range((cookie_len // 2) + 1):
offset = z16 - i
request = b'A' * offset
z16_map: Dict[int, int] = {}
z32_map: Dict[int, int] = {}
check_z32 = z32 < (len(request) + cookie_len)
for j in range(2**24):
result = _rc4_encryption_oracle(request)
try:
z16_map[result[z16]] += 1
except KeyError:
z16_map[result[z16]] = 1
if check_z32:
try:
z32_map[result[z32]] += 1
except KeyError:
z32_map[result[z32]] = 1
z16_char = max(z16_map.items(), key=itemgetter(1))[0]
plaintext[z16 - offset] = chr(z16_char ^ z16_bias)
if check_z32:
z32_char = max(z32_map.items(), key=itemgetter(1))[0]
plaintext[z32 - offset] = chr(z32_char ^ z32_bias)
print(''.join(plaintext))
return f'Recovered message "{"".join(plaintext)}"'
def main() -> Solution:
return Solution('56: RC4 Single-Byte Biases', p56)