Created
October 14, 2017 03:57
-
-
Save jaybosamiya/331d5935112c19386e68a7f57da80d8b to your computer and use it in GitHub Desktop.
Attack repeating key xor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def attack_repeating_key_xor(ciphertext, keysize=None, score=None): | |
from itertools import cycle | |
def xor(enc, k): | |
return ''.join(chr(ord(a) ^ k) for a in enc) | |
def score_english(string): | |
freq = dict() | |
freq['a'] = 834 | |
freq['b'] = 154 | |
freq['c'] = 273 | |
freq['d'] = 414 | |
freq['e'] = 1260 | |
freq['f'] = 203 | |
freq['g'] = 192 | |
freq['h'] = 611 | |
freq['i'] = 671 | |
freq['j'] = 23 | |
freq['k'] = 87 | |
freq['l'] = 424 | |
freq['m'] = 253 | |
freq['n'] = 680 | |
freq['o'] = 770 | |
freq['p'] = 166 | |
freq['q'] = 9 | |
freq['r'] = 568 | |
freq['s'] = 611 | |
freq['t'] = 937 | |
freq['u'] = 285 | |
freq['v'] = 106 | |
freq['w'] = 234 | |
freq['x'] = 20 | |
freq['y'] = 204 | |
freq['z'] = 6 | |
freq[' '] = 2320 | |
ret = 0 | |
for c in string.lower(): | |
if c in freq: | |
ret += freq[c] | |
return ret | |
if score is None: | |
score = score_english | |
if keysize is None: | |
def hamming(x, y): | |
assert(len(x) == len(y)) | |
def popcount(a): | |
if a == 0: | |
return 0 | |
else: | |
return (a % 2) + popcount(a / 2) | |
return sum(popcount(ord(a) ^ ord(b)) for a, b in zip(x, y)) | |
def norm_dist(keysize): | |
numblocks = (len(ciphertext) / keysize) | |
blocksum = 0 | |
for i in range(numblocks - 1): | |
a = ciphertext[i * keysize: (i+1) * keysize] | |
b = ciphertext[(i+1) * keysize: (i+2) * keysize] | |
blocksum += hamming(a, b) | |
blocksum /= float(numblocks) | |
blocksum /= float(keysize) | |
return blocksum | |
keysize = min(range(2, min(40, len(ciphertext))), key=norm_dist) | |
key = [None]*keysize | |
for i in range(keysize): | |
d = ciphertext[i::keysize] | |
key[i] = max(range(256), key=lambda k: score(xor(d, k))) | |
plaintext = ''.join(chr(ord(a) ^ b) for a, b in zip(ciphertext, cycle(key))) | |
return plaintext |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment