forked from reschly/cryptopals
/
prob3.py
80 lines (70 loc) · 2.53 KB
/
prob3.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
73
74
75
76
77
78
79
80
#!/usr/bin/env python
# Written against python 3.3.1
# Matasano Problem 3
# The hex encoded string:
# 1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736
# has been XOR'd against a single character. Find the key, decrypt
# the message.
# Some of the 'magic' in this comes from a college crypto course
# That course used Stinson's Cryptography book, 3rd edition
from prob1 import hexToRaw, rawToHexLUT
from prob2 import hex_xor
import string
letterFrequency = {}
letterFrequency['A'] = .082;
letterFrequency['B'] = .015;
letterFrequency['C'] = .028;
letterFrequency['D'] = .043;
letterFrequency['E'] = .127;
letterFrequency['F'] = .022;
letterFrequency['G'] = .020;
letterFrequency['H'] = .061;
letterFrequency['I'] = .070;
letterFrequency['J'] = .002;
letterFrequency['K'] = .008;
letterFrequency['L'] = .040;
letterFrequency['M'] = .024;
letterFrequency['N'] = .067;
letterFrequency['O'] = .075;
letterFrequency['P'] = .019;
letterFrequency['Q'] = .001;
letterFrequency['R'] = .060;
letterFrequency['S'] = .063;
letterFrequency['T'] = .091;
letterFrequency['U'] = .028;
letterFrequency['V'] = .010;
letterFrequency['W'] = .023;
letterFrequency['X'] = .001;
letterFrequency['Y'] = .020;
letterFrequency['Z'] = .001;
letterFrequency[' '] = .200;
# See page 35, Stinson
def calculateMG(plain):
counts = [];
for i in range(256):
counts.append(0);
for i in range(len(plain)):
if (plain[i] < 128):
counts[ord(chr(plain[i]).upper())] += 1;
result = 0.0;
for i in string.ascii_uppercase:
result += letterFrequency[i]*counts[ord(i)];
result += letterFrequency[' '] * counts[ord(' ')];
result /= len(plain);
return result;
def tryKey(cipher, key):
fullkey = key * len(cipher);
fullkey = fullkey[:len(cipher)];
potential_plain = hex_xor(cipher, fullkey);
return calculateMG(hexToRaw(potential_plain)), potential_plain;
def findGoodKeys(cipher):
for i in range(256):
mg, plain = tryKey(cipher, rawToHexLUT[i]);
#print(str(i) + ": " + str(mg));
if (mg > .050):
print("potential key: 0x" + rawToHexLUT[i]);
print("Potential hex(plain): " + str(plain).lstrip("b'").rstrip("'"));
print("potential plaintext: " + str(hexToRaw(str(plain).lstrip("b'").rstrip("'"))).lstrip("b'").rstrip("'"));
if __name__ == "__main__":
cip = b'1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736';
findGoodKeys(cip);