def break_xor(cip): e_distances = [] for KEYSIZE in range(2, 41): # 3. For each KEYSIZE, take the first KEYSIZE worth of bytes, and the second # KEYSIZE worth of bytes, and find the distance between them. Normalize this # this result by dividing by KEYSIZE. edit_dist_acc = 0 NUM_AVG = 15 for i in range(0, NUM_AVG): edit_dist_acc += hamming_d( cip[KEYSIZE * 2 * i:KEYSIZE * (2 * i + 1)], cip[KEYSIZE * (2 * i + 1):KEYSIZE * 2 * (i + 1)]) avg_edit_dist = (edit_dist_acc) / float(NUM_AVG) norm_e_dist = avg_edit_dist / float(KEYSIZE) e_distances.append((KEYSIZE, norm_e_dist)) # 4. The KEYSIZE with the smallest normalized edit distance is probably the key. # You could proceed perhaps with the smallest 2-3 KEYSIZE values. sorted_dist = sorted(e_distances, key=operator.itemgetter(1)) #**DEBUG** #for i in sorted_dist: # print i for KEYSIZE, norm_edit_dist in sorted_dist[:1]: # 5. Now that you probably know the KEYSIZE: break the ciphertext into blocks # of KEYSIZE length. Now transpose the blocks: make a block that is the first # byte of each block, and block that is the second bytes, and so on. block_cip = ['' for i in range(0, KEYSIZE)] for index, char in enumerate(cip): block_cip[index % KEYSIZE] += char # 7. Solve each block as if it was single-character XOR. key = '' for block in block_cip: key += chr(sbx.decrypt(block.encode('hex'))[0]) print "GUESSED KEY:\n " + key print "MESSAGE:\n" + rx.rep_xor(cip, key).decode('hex')
def get_xor_bytes(blocks, score_fn): l = len(blocks) xor_bytes = [None for i in range(l)] for i in range(l): (_, _, xor_bytes[i]) = singlebytexor.decrypt(blocks[i], score_fn) return bytearray(xor_bytes)
def break_xor(cip): '''Breaks repeating XOR. @arg cip The cipher text, in raw bytes (i.e. not encoded in any form). @return None. Displays the probable key guesses. ''' e_distances = [] for KEYSIZE in range(2, 41): # 3. For each KEYSIZE, take the first KEYSIZE worth of bytes, and the second # KEYSIZE worth of bytes, and find the distance between them. Normalize this # this result by dividing by KEYSIZE. edit_dist_acc = 0 NUM_AVG = 15 for i in range(0, NUM_AVG): edit_dist_acc += hamming_d(cip[KEYSIZE*2*i:KEYSIZE*(2*i + 1)], cip[KEYSIZE*(2*i + 1):KEYSIZE*2*(i+1)]) avg_edit_dist = (edit_dist_acc) / float(NUM_AVG) norm_e_dist = avg_edit_dist / float(KEYSIZE) e_distances.append((KEYSIZE, norm_e_dist)) # 4. The KEYSIZE with the smallest normalized edit distance is probably the key. # You could proceed perhaps with the smallest 2-3 KEYSIZE values. You could # also take the average of the edit distances of the first few blocks. sorted_dist = sorted(e_distances, key=operator.itemgetter(1)) #**DEBUG** debug = open("/tmp/break_xor_debug-" + strftime("%d-%b-%Y-%H-%M-%S", gmtime()), "w") for i in sorted_dist: debug.write(str(i) + "\n") debug.close() for KEYSIZE, norm_edit_dist in sorted_dist[:1]: # 5. Now that you probably know the KEYSIZE: break the ciphertext into blocks # of KEYSIZE length. Now transpose the blocks: make a block that is the first # byte of each block, and block that is the second bytes, and so on. block_cip = ['' for i in range(0, KEYSIZE)] for index, char in enumerate(cip): block_cip[index % KEYSIZE] += char # 7. Solve each block as if it was single-character XOR. key = '' for block in block_cip: key += chr(sbx.decrypt(block.encode('hex'))[0]) print "GUESSED KEY:\n " + key print "MESSAGE:\n" + rx.rep_xor(cip, key).decode('hex')
import singlebytexor as sbx for l in open('4.txt').readlines(): # try to decrypt every single 'ciphertext' s = sbx.decrypt(l.strip()) # if it yields an interesting (i.e. printable) result, display it. if sbx.printable(s[1]): print s
from singlebytexor import score, decrypt with open("4.txt", "r") as f: for line in f.read().split("\n"): d = decrypt(line) if d is not None: print line, d # 7b5a4215415d544115415d5015455447414c155c46155f4058455c5b523f Now that the party is jumping