Tags: xor web javascript 

Rating:

Python Code to solve this challenge:
```
import os
import collections
import itertools

def kasiski(text, offset):
c = 0
for i in range(0, len(text)):

# If we find somewhere else the same character, increment counter
if text[i] == text[(i + offset) % len(text)]:
# Hint!
c += 1
return c

# Encrypted text
hex = "\x0d\x13\x45\x17\x48\x09\x5e\x4b\x17\x3c\x1a\x1f\x2b\x1b\x7a\x0c\x1f\x66\x0b\x1a\x3e\x51\x0b\x41\x11\x58\x17\x4d\x55\x16\x42\x01\x52\x4b\x0f\x5a\x07\x00\x00\x07\x06\x40\x4d\x07\x5a\x07\x14\x19\x0b\x07\x5a\x4d\x03\x47\x01\x13\x43\x0b\x06\x50\x06\x13\x7a\x02\x5d\x4f\x5d\x18\x09\x41\x42\x15\x59\x48\x4d\x4f\x59\x1d\x43\x10\x15\x00\x1a\x0e\x17\x05\x51\x0d\x1f\x1b\x08\x1a\x0e\x03\x1c\x5d\x0c\x05\x15\x59\x55\x09\x0d\x0b\x41\x0e\x0e\x5b\x10\x5b\x01\x0d\x0b\x55\x17\x02\x5a\x0a\x5b\x05\x10\x0d\x52\x43\x40\x15\x46\x4a\x1d\x5f\x4a\x14\x48\x4b\x40\x5f\x55\x10\x42\x15\x14\x06\x07\x46\x01\x55\x16\x42\x48\x10\x4b\x49\x16\x07\x07\x08\x11\x18\x5b\x0d\x18\x50\x46\x5c\x43\x0a\x1c\x59\x0f\x43\x17\x58\x11\x04\x14\x48\x57\x0f\x0a\x46\x17\x48\x4a\x07\x1a\x46\x0c\x19\x12\x5a\x22\x1f\x0d\x06\x53\x43\x1b\x54\x17\x06\x1a\x0d\x1a\x50\x43\x18\x5a\x16\x07\x14\x4c\x4a\x1d\x1e"

# Generate offsets: 1 - 20
offsets = range(1,20)

for o in offsets:
print("Offset: %d\tOccurences: %d" % (o, kasiski(hex, o)))

def countletters(myfile):
""" Returns a dictionary containing a occurence frequency of each found character"""
d = collections.defaultdict(int)
myfile = open(myfile)
for line in myfile:
line = line.rstrip('\n')
for c in line:
d[c] += 1
return d

def get_letters_count(myfile):
""" Gets amount of characters in myfile """
with open(myfile) as f:
c = f.read()
return len(c)

filename = 'jq.js' #jQuery 3.1.0 file
freqs = countletters(filename)
file_size = get_letters_count(filename)

percent_freqs = {}
for k,v in freqs.iteritems():
# Save ASCII code of letter and its occurence frequency
percent_freqs[ord(k)] = "{0:.8f}".format(v/float(file_size))

# For all other unoccured letters, store occurence = 0
for i in xrange(0, 256):
if not i in percent_freqs:
percent_freqs[i] = "{0:.8f}".format(0)

def chi_squared(ciphertext, freqs):
d = collections.Counter(ciphertext)
res = []

for k,v in freqs.iteritems():
c = 0
decrypted = []

for i in ciphertext:
# Do the XOR operation
decrypted.append(chr(k ^ ord(i)))

for l in decrypted:
expected_count = float(len(ciphertext) * float(freqs[ord(l)]))
real_count = float(d[l])

# Avoid division by 0
if expected_count > 0:
c+= (real_count - expected_count ** 2) / expected_count

res.append(c)

return res

def make_columns(text, key_length):
""" Returns columns of length = key_length for text"""
blocks = []

# Divide ciphertext into blocks of length = key_length
for i in xrange(0, len(text)/key_length):
blocks.append(list(text[key_length*i:key_length*i+key_length]))

# Create list: [[blocks[0][0], blocks[0][1], ...], [blocks[1][0], blocks[1][1], ...]]
columns = map(list,zip(*blocks))

# What about remaining text that doesn't fit into one block?
if len(text) % key_length:
remaining = text[key_length*(len(text)/key_length)]
for i in xrange(len(remaining)):
columns[i].append(remaining[i])
return columns

columns = make_columns(hex, 9)
key = ''

for i in columns:
res = chi_squared(i, percent_freqs)
key += chr(res.index(min(res)))

#print key
key = 'dumbh4ck5'

def xor(message,key):
return ''.join(chr(ord(c)^ord(k)) for c,k in itertools.izip(message, itertools.cycle(key)))

print(xor(hex, key))

```